How to use #Qualifier in Hibernate - java

My hibernate configuration class is below.
#Configuration
#EnableTransactionManagement
#ComponentScan({ "com.span.vms.configuration" })
#PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {
#Autowired
private Environment environment;
#Bean
#Primary
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.span.vms.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public LocalSessionFactoryBean sessionFactoryActiviti() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSourceActiviti());
sessionFactory.setPackagesToScan(new String[] { "com.span.vms.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
#Bean(name = "dataSourceActiviti")
public DataSource dataSourceActiviti() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.activiti.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
When I run this via spring boot I am getting error saying "expected single matching bean but found 2: datasource and dataSourceActiviti".
I added name to each bean. But how can use #Qualifier here?

You can make one of the DataSource primary by annotating it with #Primary.

Related

Unable to solve error "save is not valid without active transaction"

I'm unable to solve error
save is not valid without active transaction
my code:
public class PersistenceJPAConfig {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "self.experiment.dto" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf) {
return hemf.getSessionFactory();
}
#Bean
public EntityManager entityManager(){
return entityManagerFactory().getObject().createEntityManager();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
hibernateTransactionManager.setSessionFactory(sessionFactory);
return hibernateTransactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.setProperty("hibernate.current_session_context_class", "thread");
properties.setProperty("hibernate.show_sql", "false");
return properties;
}
}
public class UserBL {
#Autowired
UserDAO userDao;
#Transactional(transactionManager="transactionManager")
public void saveUsers(){
User user = new User();
user.setName("Bob");
userDao.insert(user);
}
}
On a lot of blogs i have read that removing hibernate.current_session_context_class from JPA property will fix this problem. But when i remove it i get following error
No CurrentSessionContext configured!
You are configuring a SessionFactory and an EntityManagerFactory. Remove all the Hibernate specific stuff:
#Configuration
public class PersistenceJPAConfig {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "self.experiment.dto" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.setProperty("hibernate.show_sql", "false");
return properties;
}
}
Service
public class UserBL {
#Autowired
UserDAO userDao;
#Transactional
public void saveUsers(){
User user = new User();
user.setName("Bob");
userDao.insert(user);
}
}
DAO
public class UserDAO {
#PersistenceContext
private EntityManager em;
}

How do I configure Hibernate Console in Intellij with java config?

I have a Persistence configured in Java. No persistence.xml. Intellij shows me the entityManagerFactory and the entities in the Persistence window. The query runs OK in the application.
How do I get the hibernate console in Intellij to run queries?
I get
[2016-09-12 14:09:07] java.lang.NoSuchMethodError: org.hibernate.Session.createQuery(Ljava/lang/String;)Lorg/hibernate/Query
The dialect is hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
The configuration is:
#Configuration
#EnableTransactionManagement
#PropertySource({ "file:${view.config}" })
#ComponentScan({ "my.me.model" })
public class PersistenceConfig {
private static Logger logger = LoggerFactory.getLogger(PersistenceConfig.class);
#Autowired
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("my.me.model");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibernateProperties());
return em;
}
#Bean
#Autowired
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
#SuppressWarnings("serial")
Properties hibernateProperties() {
return new Properties() {
{
setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
setProperty("hibernate.globally_quoted_identifiers", "true");
setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
}
};
}
This now works in 2106.3 EAP. The answer is to upgrade.

How to include Spring JPA in the existing Spring Hibernate application

I am working on one enhancement in my application. This application is Spring Hibernate implementation.But the enhancement now I am working is Spring-JPA.
Without disturbing the existing implementation I need to include JPA
Below is my DBconfiguration class.
#Configuration
#EnableJpaRepositories(basePackages = {"packagename","package name" })
#EnableTransactionManagement
public class DataBaseConfiguration {
#Value("${postgres.driver}")
private String postgresDriver;
#Value("${postgres.url}")
private String postgresUrl;
#Value("${postgres.username}")
private String postgresUsername;
#Value("${postgres.password}")
private String postgresPassword;
#Value("${hibernate.dialect}")
private String hibernateDialect;
#Value("${hibernate.dialect.property}")
private String dialectProperty;
#Value("${hibernate.show-sql}")
private String hibernateShowSql;
#Value("${boolean.true}")
private String booleanTrue;
**\\ existing hibernate flow**
#Autowired
#Bean(name = "name")
public SessionFactory getSessionFactory(DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(
dataSource);
sessionBuilder.addAnnotatedClasses(entity.class);
sessionBuilder.setProperty(hibernateDialect, dialectProperty);
sessionBuilder.setProperty(postgresDriver, postgresUrl);
sessionBuilder.setProperty(hibernateShowSql, booleanTrue);
return sessionBuilder.buildSessionFactory();
}
**\\ existing hibernate flow**
#Bean(name = "name")
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(postgresDriver);
dataSource.setUrl(postgresUrl);
dataSource.setUsername(postgresUsername);
dataSource.setPassword(postgresPassword);
return dataSource;
}
**\\ existing hibernate flow**
#Autowired
#Bean(name = "manager")
public HibernateTransactionManager getTransactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = null;
transactionManager = new HibernateTransactionManager(sessionFactory);
return transactionManager;
}
**\\included newly for JPA**
#Bean
public org.springframework.orm.jpa.JpaTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(getDataSource());
jpaTransactionManager
.setJpaDialect(new org.springframework.orm.jpa.vendor.HibernateJpaDialect());
return jpaTransactionManager;
}
**\\included newly for JPA**
#Bean
public EntityManager entityManger() {
return entityManagerFactory().getObject().createEntityManager();
}
\\included newly for JPA
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(getDataSource());
entityManagerFactory.setPackagesToScan(
"some package",
"some package");
Map<String, Object> jpaProperty = entityManagerFactory
.getJpaPropertyMap();
jpaProperty.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
va.setShowSql(Boolean.valueOf("true"));
entityManagerFactory.setJpaVendorAdapter(va);
return entityManagerFactory;
}
}
When I deployed this application i am getting below exception
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class ------
Caused by: java.lang.NullPointerException
at org.hibernate.hql.internal.antlr.HqlBaseParser.identPrimary(HqlBaseParser.java:4285)
at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:980)
at org.hibernate.hql.internal.antlr.HqlBaseParser.atom(HqlBaseParser.java:3609)
at org.hibernate.hql.internal.antlr.HqlBaseParser.unaryExpression(HqlBaseParser.java:3387)
at org.hibernate.hql.internal.antlr.HqlBaseParser.multiplyExpression(HqlBaseParser.java:3259)
at org.hibernate.hql.internal.antlr.HqlBaseParser.additiveExpression(HqlBaseParser.java:2964)
at org.hibernate.hql.internal.antlr.HqlBaseParser.concatenation(HqlBaseParser.java:597)
at org.hibernate.hql.internal.antlr.HqlBaseParser.relationalExpression(HqlBaseParser.java:2730)
at org.hibernate.hql.internal.antlr.HqlBaseParser.equalityExpression(HqlBaseParser.java:2591)
at org.hibernate.hql.internal.antlr.HqlBaseParser.negatedExpression(HqlBaseParser.java:2555)
at org.hibernate.hql.internal.antlr.HqlBaseParser.logicalAndExpression(HqlBaseParser.java:2471)
at org.hibernate.hql.internal.antlr.HqlBaseParser.logicalOrExpression(HqlBaseParser.java:2436)
at org.hibernate.hql.internal.antlr.HqlBaseParser.expression(HqlBaseParser.java:2146)
at org.hibernate.hql.internal.antlr.HqlBaseParser.exprList(HqlBaseParser.java:3994)
at org.hibernate.hql.internal.antlr.HqlBaseParser.identPrimary(HqlBaseParser.java:4278)
I would suggest another approach, which could be simpler. Make JPA leading and use the LocalContainerEntityManagerFactoryBean to configure everything (including what you use now for hibernate). Next use the HibernateJpaSessionFactoryBean to expose the underlying SessionFactory.
This would save you duplicate configuration and would allow you to use a single JpaTransactionManager for all your transactions, however you still would be able to use a SessionFactory or HibernateTemplate if you would.
#Configuration
#EnableJpaRepositories(basePackages = {"packagename","package name" })
#EnableTransactionManagement
public class DataBaseConfiguration {
#Autowired
private Environment env;
#Autowired
#Bean(name = "name")
public FactoryBean<SessionFactory> getSessionFactory(EntityManagerFactory emf) {
HibernateJpaSessionFactoryBean factory = new HibernateJpaSessionFactoryBean();
factory.setEntityManagerFactory(emf);
return factory;
}
**\\ existing hibernate flow**
#Bean(name = "name")
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("postgres.driver"));
dataSource.setUrl(env.getRequiredProperty("postgres.url);
dataSource.setUsername(env.getRequiredProperty("postgres.username");
dataSource.setPassword(env.getRequiredProperty("postgres.password");
return dataSource;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(getDataSource());
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory());
return jpaTransactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(getDataSource());
Map<String, String> properties = new HashMap<String, String>();
properties.put("hibernate.current_session_context_class", SpringSessionContext.class.getName());
entitytManagerFactory.setJpaPropertyMap(properties);
entityManagerFactory.setPackagesToScan(
"some package",
"some package");
HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
va.setShowSql(env.getProperty("hibernate.show-sql", Boolean.class, true);
va.setDatabasePlatform(env.getProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
entityManagerFactory.setJpaVendorAdapter(va);
return entityManagerFactory;
}
}

Spring Advice object [null] using JdkDynamicAopProxy

Using an injected spring service service.listAll() i have the exception below :
Caused by: org.springframework.aop.framework.adapter.UnknownAdviceTypeException:
Advice object [null] is neither a supported subinterface of
[org.aopalliance.aop.Advice] nor an [org.springframework.aop.Advisor]
at org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry.getInterceptors(DefaultAdvisorAdapterRegistry.java:88)
at org.springframework.aop.framework.DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(DefaultAdvisorChainFactory.java:61)
at org.springframework.aop.framework.AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport.java:482)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:188)
The Configuration Class
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:system/db.properties")
#ComponentScan("com.agitech.agitech.service")
public class ContextConfig {
protected static Log log = LogFactory.getLog(ContextConfig.class);
#Resource
private Environment env;
public void setEnv(Environment env) {
this.env = env;
}
private final Properties hibProperties() {
Properties properties = new Properties();
properties.put( HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT) );
properties.put( HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL) );
properties.put( "hibernate.bytecode.provider", "javassist" );
properties.put( "hibernate.listeners.envers.autoRegister", false );
return properties;
}
#Bean(name ="dataSource")
public DataSource dataSource() {
return dataSource( env.getRequiredProperty(DATABASE_URL) );
}
#Bean(name ="mgrJPA")
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
public DataSource dataSource(String url) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
dataSource.setUrl(url);
dataSource.setUsername(env.getRequiredProperty(DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
return dataSource;
}
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource, String unitName, String... packages) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean =
new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource( dataSource );
entityManagerFactoryBean.setPersistenceProviderClass( HibernatePersistence.class );
entityManagerFactoryBean.setPackagesToScan( packages );
entityManagerFactoryBean.setJpaProperties( hibProperties() );
entityManagerFactoryBean.setPersistenceUnitName( unitName );
return entityManagerFactoryBean;
}
#Bean(name ="mgrEMF")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
return entityManagerFactory(dataSource(), "mgrUnit", Contract.class.getPackage().getName());
}
}
The problem was that i didn't annotade the listAll procedure of the Service with the #Transactional annotation, but i thought that given that its just select query i dont need a transaction
Most probably you are missing <context:annotation-config/> in your Spring configuration file therefore interceptor doesn't get injected into PointcutAdvisor

working with two transactions, one seem to work but the other does not. why?

I'm working with two transactions on spring which has reference to two entitymanagers and hence two datasources, while using #Transactional("transaction1") it works fine but #Transactional("transaction2") throws out an error saying no active transactions found. following is the piece of code:
#Bean(name = "transaction1")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean2()
.getObject());
return transactionManager;
}
#Bean(name = "transaction2")
public PlatformTransactionManager sermaTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager
.setEntityManagerFactory(entityManagerFactoryBean1()
.getObject());
return transactionManager;
}
respective entitymanagers:
#Bean(name = "entitymanager1")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean1() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource1());
entityManagerFactoryBean
.setPackagesToScan(new String[] { this.environment
.getProperty("db.packagesToScan") });
entityManagerFactoryBean
.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter());
Map<String, Object> jpaProperties = new HashMap<String, Object>();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", "INFO");
jpaProperties.put("eclipselink.logging.parameters", "true");
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
return entityManagerFactoryBean;
}
#Bean(name = "entitymanager2")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean2() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource2());
entityManagerFactoryBean
.setPackagesToScan(new String[] { this.environment
.getProperty("db.packagesToScan") });
entityManagerFactoryBean
.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter());
Map<String, Object> jpaProperties = new HashMap<String, Object>();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.parameters", "true");
jpaProperties.put("eclipselink.logging.level", "INFO");
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
return entityManagerFactoryBean;
}
respective datasources:
#Bean("datasource1")
public DriverManagerDataSource dataSource1() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource .setDriverClassName(this.environment.getProperty("db.driver"));
dataSource.setUrl(this.environment.getProperty("db.url"));
dataSource.setUsername(this.environment
.getProperty("db.username.abc"));
dataSource.setPassword(this.environment
.getProperty("db.password.abc"));
return dataSource;
}
#Bean("datasource2")
public DriverManagerDataSource dataSource2() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource
.setDriverClassName(this.environment.getProperty("db.driver"));
dataSource.setUrl(this.environment.getProperty("db.url"));
dataSource.setUsername(this.environment.getProperty("db.username"));
dataSource.setPassword(this.environment.getProperty("db.password"));
return dataSource;
}
My genericDaoImpl has the following to link respective entitymanagers:
#PersistenceContext(unitName = "entitymanager1")
private EntityManager em1;
#PersistenceContext(unitName = "entitymanager2")
private EntityManager em2;
when i do #Transactional("transaction1") it works fine, but when i do #Transactional("transaction2") it says no active transactions. and when i dont mention the qualifier for the transactions, error says two transactions found (transaction1, transaction2). any help would be great.
There is an issue with the config:
The problem is that when the beans are initialized like this:
transactionManager.setEntityManagerFactory(entityManagerFactoryBean2().getObject());
The call to entityManagerFactoryBean2() will create a new entity manager factory, and then the #Bean annotation will trigger the creation of another entity manager factory, with the same config.
When you inject the entity manager factory with #Autowiredin a bean, you are injecting the instance created with #Bean, and not the instance passed to the transaction manager.
One warning concerning the config:
The config above allows to do transactions in two separate datasources, but it's not possible with this config to do transactions that span the two databases. For example:
#Service
public class PlanesService {
#PersistenceContext(unitName = "entityManagerFactory1")
private EntityManager em1;
#PersistenceContext(unitName = "entityManagerFactory2")
private EntityManager em2;
#Transactional("transactionManager1")
public Plane savePlanes() {
F14 f14 = new F14("F14","f14");
F16 f16 = new F16("F16","f16");
em1.persist(f14);
em2.persist(f16);
return f14;
}
}
This code will only persist f14, because the only entity manager that has an ongoing transaction is em1 (due to #Transactional("transactionManager1")). The call to em2.persist() will be ignored (em2 can still do reads though).
If you want to do transactions that include both databases you need a JTA transaction manager.
An example of a working config:
This an example of a configuration that fixes the above injection issues:
#Configuration
public class DataSourcesConfig {
#Bean(name = "datasource1")
public DriverManagerDataSource dataSource1() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
...
return dataSource;
}
#Bean(name = "datasource2")
public DriverManagerDataSource dataSource2() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
...
return dataSource;
}
}
#Configuration
public class EntityManagerFactoriesConfiguration {
#Autowired
#Qualifier("datasource1")
private DataSource dataSource1;
#Autowired
#Qualifier("datasource2")
private DataSource dataSource2;
#Bean(name = "entityManagerFactory1")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource1);
entityManagerFactoryBean.setPackagesToScan(new String[] { "your.package.here" });
entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Map<String, Object> jpaProperties = new HashMap<String, Object>();
...
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
return entityManagerFactoryBean;
}
#Bean(name = "entityManagerFactory2")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean2() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource2);
entityManagerFactoryBean.setPackagesToScan(new String[] { "your.package.here" });
entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Map<String, Object> jpaProperties = new HashMap<String, Object>();
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
...
return entityManagerFactoryBean;
}
}
#Configuration
#EnableTransactionManagement
public class TransactionManagersConfig {
#Autowired
#Qualifier("entityManagerFactory1")
EntityManagerFactory entityManagerFactory1;
#Autowired
#Qualifier("entityManagerFactory2")
EntityManagerFactory entityManagerFactory2;
#Autowired
#Qualifier("datasource1")
private DataSource dataSource1;
#Autowired
#Qualifier("datasource2")
private DataSource dataSource2;
#Bean(name = "transactionManager1")
public PlatformTransactionManager transactionManager1() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory1);
transactionManager.setDataSource(dataSource1);
return transactionManager;
}
#Bean(name = "transactionManager2")
public PlatformTransactionManager transactionManager2() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory2);
transactionManager.setDataSource(dataSource2);
return transactionManager;
}
}
By splitting the config in several #Configuration classes and autowiring them, we ensure that it's always the same beans being used (singletons).
Notice the #EnableTransactionManagement annotation, that enables #Transactional.

Categories

Resources