How to setup JTA with multiple XA datasoures for Spring JPA? - spring

Spring JPA 4.2.1
Trying to setup JTA with 2 XA datasoures looks like below but gets NoUniqueBeanDefinitionException
"No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: emf_1,emf_2"
<bean id="emf_1"
class="...LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xa_1" />
</bean>
<bean id="emf_2"
class="...LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xa_2" />
</bean>
#Repository
public class DAO {
#PersistenceContext#Qualifier("emf_1")
private EntityManager em_1;
#PersistenceContext#Qualifier("emf_2")
private EntityManager em_2;
/*...*/
}
How to make it work?

#Solution
It works below now,
<bean class="...LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xa_1" />
<property name="persistenceUnitName" value="pu_1" />
</bean>
<bean class="...LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xa_2" />
<property name="persistenceUnitName" value="pu_2" />
</bean>
#Repository
public class DAO {
#PersistenceContext(unitName = "pu_1")
private EntityManager em_1;
#PersistenceContext(unitName = "pu_2")
private EntityManager em_2;
/*...*/
}
<persistence-unit name="pu_1" transaction-type="JTA">
...
</persistence-unit>
<persistence-unit name="pu_2" transaction-type="JTA">
...
</persistence-unit>

Related

Spring 4 + Hibernate 5.1 Transaction auto committed after call another DAO query

I have a problem with transaction auto committed after call another dao native query.
Both service and dao signed as #Transactional.
What am I doing wrong here?
Spring 4.2.x
Hibernate 5.1.0
Atomikos 3.9.3
This is my setup:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="jtaPlatformAdapter" class="com.xxx.JtaPlatformAdapter">
<property name="jtaTransactionManager" ref="transactionManager" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionManager" destroy-method="close" id="atomikosTransactionManager" init-method="init">
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="true" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionImp" id="atomikosUserTransaction" />
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="transactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<bean id="datasouce" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
...
</bean>
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" id="JPAVendorAdapter">
...
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emf" depends-on="transactionManager,jtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="com.xxx.server"/>
<property name="dataSource" ref="datasouce" />
<property name="persistenceUnitName" value="pun" />
<property name="jpaVendorAdapter" ref="JPAVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.connection.release_mode" value="on_close" />
<entry key="hibernate.transaction.jta.platform" value="com.xxx.server.JtaPlatformAdapter" />
</map>
</property>
</bean>
persistence.xml
<persistence-unit name="pun" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
service
#Transactional
#Scope("prototype")
public synchronized void save(EntityObj model) throws Exception {
model.setX(30);
model.setY(40);
EntityObj oldModel = entityObjDAO.findById(model.getId());
// after call findById, the model had been commit to DB
...
...
...
entityObjDAO.store(model); // this will call entityManager.merge(model)
entityObjDAO.flush();
}
DAO
#Transactional
public EntityObj findById(String id) {
EntityObj model = null;
String sql = "select id,x,y from EntityObj where id = :id"; // this is a native sql query
Query query = this.entityManager.createNativeQuery(sql);
query.setParameter("id", id);
Object[] rs = (Object[]) query.getSingleResult();
if (rs != null) {
model = new EntityObj();
model.setId(id);
model.setX(rs[1] == null ? null : (Integer) rs[1]);
model.setY(rs[2] == null ? null : (Integer) rs[2]);
}
return model;
}
thanks!
If you are using #Transactional in your code, Spring creates a proxy object for your Dao object (wrapper).
So it looks like this if your application is running:
public EntityObj proxyMethodForFindById(String id) {
try {
// 1. start transaction
startTransaction();
// 2. execute your code
return yourDaoObject.findById(id);
} finally { // [!] PSEUDO CODE: NO EXCEPTION HANDLING
// commit transaction
commitTransaction();
}
}
So what happens in your code?
Your save method is marked also as #Transactional. So if you are changing your object by setting:
model.setX(30);
model.setY(40);
Spring creates two proxies. One for Service and one four your Dao. On the End of the findById-Transaction this changes will be commited. Nested transactions is the keyword.
You should remove #Transaction in your findById-Method or better in the whole Dao object. Service should be transactional, not Dao-layer.

Spring 4 Jpa Hibernate - Can't Inject EntityManager

I guess I have the same problem as many people, but unsolved on most of cases. I will try anyway, hope you guys can help me.
The problem is in my repository when I try to inject que Entity Manager using #persistenceContext annotation and always comes null.
The stack:
Spring 4.2.5
Spring Data 1.10.1
Hibernate 5
This is my xml for Sprint data:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="conquerPU"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="com.conquer.module" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL82Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/conquer" />
<property name="username" value="app" />
<property name="password" value="10203040" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
<bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<jpa:repositories base-package="com.conquer.module" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>
This is my application context.xml
<context:annotation-config/>
<context:component-scan base-package="com">
<context:include-filter type="aspectj" expression="com.*" />
</context:component-scan>
<!-- a HTTP Session-scoped bean exposed as a proxy -->
<bean id="sessionData" class="com.conquer.common.SessionData" scope="session">
<aop:scoped-proxy/>
</bean>
<!--Hibernate persistence interceptor - Used for audit data-->
<bean id="hibernateInterceptor" class="com.conquer.module.security.interceptor.HibernateInterceptor"></bean>
<!--Application Context to be used anywhere-->
<bean id="applicationContextProvder" class="com.conquer.common.ApplicationContextProvider"/>
<!-- SpringMVC -->
<import resource="spring-mvc.xml"/>
<!-- SpringData -->
<import resource="spring-jpa.xml"/>
<!-- SpringSecurity -->
<import resource="spring-security.xml"/>
This is my repository
#Repository
#Transactional
public class BaseRepositoryImpl<T, ID extends Serializable> implements BaseRepository<T, ID> {
#PersistenceContext
public EntityManager em;
public RepositoryFactorySupport baseFactory;
public BaseRepository<T, ID> baseRepository;
public BaseRepositoryImpl() {
System.out.println("BASE REPOSITORY RUNNING...");
this.baseFactory = new JpaRepositoryFactory(em);
this.baseRepository = this.baseFactory.getRepository(BaseRepository.class);
}
// Implementations here ...
}
This is my persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="conquerPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect"/>
<property name = "hibernate.show_sql" value = "true" />
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.ejb.interceptor" value="com.conquer.module.security.interceptor.HibernateInterceptor"/>
</properties>
</persistence-unit>
</persistence>
Although this question is quite old, we faced with this problem as well and solved it by adding this bean to our application context:
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
The documentation for context:annotation-config clearly states that this should not be necessary, but in our case it was (albeit we use Spring 4.2 inside Eclipse Virgo 3.7 with Gemini Blueprint, so this setup is probably far from mainstream).

spring Multi DataSource #Service annotation with existing error

I have a code that is an error in the Spring Framework
Error Cause I know
So I do not know how to solve it the question.
I am being used with mybatis library
I had multi DataSource of two Account DataBase
I created a root-context.xml
-----------------------root-context.xml -----------------------------------------------------------
Oracle Account 1 Test1
<bean id="dataSourceTest1" class="org.apache.commons.dbcp.BasicDataSource" destroy-m
ethod="close">
<property name="driverClassName" value="net.sf.log4jdbc.DriverSpy"/>
<property name="url" value="jdbc:log4jdbc:oracle:thin:#111.111.1111.1111:1111:Test1"/>
<property name="username" value="TEST1"/>
<property name="password" value="TEST1"/>
<property name="maxIdle" value="200"/>
<property name="maxActive" value="200"/>
<property name="minIdle" value="5"/>
</bean>
<bean id="sqlSessionFactoryTest1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourceTest1" />
<property name="mapperLocations" value="classpath*:test/service/server/test1/**/*.xml" />
</bean>
<bean id="sqlSessionTest1" class="org.mybatis.spring.SqlSessionTemplate" name="sqlSessionTest1">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryTest1" />
</bean>
<mybatis-spring:scan base-package="test.service.server.test1" template-ref="sqlSessionTest1" />
Oracle Account test2
<bean id="dataSourceTest2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="net.sf.log4jdbc.DriverSpy"/>
<property name="url" value="jdbc:log4jdbc:oracle:thin:#222.222.2222.222:2222:Test2"/>
<property name="username" value="Test2"/>
<property name="password" value="Test2"/>
<property name="maxIdle" value="200"/>
<property name="maxActive" value="200"/>
<property name="minIdle" value="5"/>
</bean>
<bean id="sqlSessionFactoryTest2" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourceTest2" />
<property name="mapperLocations" value="classpath*:test/service/server/test2/**/*.xml" />
</bean>
<bean id="sqlSessionTest2" class="org.mybatis.spring.SqlSessionTemplate" name="sqlSessionTest2">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryTest2" />
</bean>
<mybatis-spring:scan base-package="test.service.server.test2" template-ref="sqlSessionTest2"/>
-----------------------root-context.xml END ---------------------------------------------------------
i am not used context:component-scan
<!-- <context:component-scan base-package="test.service.server.test1.test1service"/>-->
<!-- <context:component-scan base-package="test.service.server.test2.test2service"/>-->
I use the SpringJUnit4 each unit test
Were sequentially to (DataSourceTest and SqlSessionFactory Test and SqlSession Test mapperScanTest).
did not have any problems until mapperScanTest.
However, an error occurs when star using the annotation # Service
------------------------------------------service interface code ------------------------------------
public interface Test2_SERVICE {
public List<Test2_VO> GET_ListVO();
}
-------------------------------------------implement service code----------------------------------
#Service("Test2_SERVICE") *//<--Error annotaion*
public class Test2_SERVICEIMPLE implements Test2_SERVICE{
#Resource
Test2_MAPPER mapper;
#Override
public List<Test2_VO> GET_ListVO() {
return mapper.GET_ListMapperVO();
}
}
---------test Code------------------------------
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/**/*-context.xml" })
public class TestService {
Logger logger = Logger.getLogger(Thread.currentThread().getClass());
#Autowired
#Qualifier("Test2_SERVICE")
Test2_SERVICE test2_SERVICE;
#Override
public void testString() {
logger.info("---------------------");
List<Test2_VO> listVO = test2_SERVICE.GET_ListVO();
logger.info(listVO );
logger.info("---------------------");
}
}
Error Messages-----------------------------------
Caused by:
org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'Test2_SERVICE' for bean class
[test.service.server.test2.test2service.Test2_SERVICE] conflicts with
existing, non-compatible bean definition of same name and class
[test.service.server.test2.test2service.Test2_SERVICEIMPLE]
------------------------------------------------end---------------------------------------------
#Service("Test2_SERVICE") *//<--Error annotaion*
The problem did not exist until the object Test2_MAPPER
However, the error begins in Test2_SERVICE
# Service ("Test2_SERVICE") Where there is only used here (Test2_SERVICEIMPLE).
Because of this problem
I am suffering for three days..
Somebody tell me solve the problem for this error message.
Thank you for reading my article.
The problem is that you create a bean with the name "Test2_SERVICE" for Test2_SERVICEIMPLE with this annotation:
#Service("Test2_SERVICE")
//creates the bean with id="TEST2_Service" of the type Test2_SERVICEIMPLE
public class Test2_SERVICEIMPLE implements Test2_SERVICE
and then assign exactly this Test2_SERVICEIMPLE bean to the interface Test2Service
#Autowired
#Qualifier("Test2_SERVICE")
//here you assign the bean of the not matching type Test2_SERVICEIMPLE to
//a variable of type Test2_SERVICE
Test2_SERVICE test2_SERVICE;
That means that the interface wants to use the bean for the implementation...
So just remove/change the #Qualifier("Test2_SERVICE") or change the name of the #Service("Test2_SERVICE")
How to autowire annotation qualifiers and how to name autodetected components

EntityManager not injected from factory

I'm using JPA/Hibernate to build a web app. I'm using a LocalContainerEntityManagerFactoryBean with <property name="packagesToScan" value="<pkg>" /> to build my entities from a java package, and a jdbc.datasource.DriverManagerDataSource configured for PostgreSQL, so I don't have a defined persistence context.
Can I build an EntityManager with these constraints, using either Spring annotations or xml?
EDIT:
I'm using a code of the following form to get a user data for login. In the Spring Security context the EntityManager is always null.
#Repository
public class UserDao implements UserDetailsService {
#PersistenceContext
private EntityManager entityManager; // With getter and setter
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
// Used by spring-security, here entityManager is null
}
}
EDIT2: Added context configuration
<context:spring-configured />
<context:annotation-config />
<context:component-scan base-package="<BasePackage>" />
EDIT3: Added entity manager factory config:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="default_unit" />
<property name="dataSource" ref="dataSource" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
</bean>
</property>
<property name="packagesToScan" value="<package>" />
<property name="jpaProperties">
<value>
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.hbm2ddl.auto=create-drop
hibernate.hbm2ddl.import_files=/loaded-on-startup/import.sql
<!-- ALSO CHECK IMPORT.SQL -->
</value>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
/// CONNECTION CONFIG ///
</bean>
I also have added default-autowire="byType" to my beans tag and autowire="byType" to the security authentication bean definition.
Yes. Take a look here . You need to provide a datasource and use LocalContainerEntityManagerFactoryBean bean
Edit
It may be because of no transaction available.Read here

Autowire Jdbc template

I am trying to auto-wire JDBC template and I'm getting a null pointer exception (template is null). What could be the problem?
#Autowired
template JdbcTemplate;
This is my application context xml:
<bean ..>
<mvc:annotation-driven />
<context:component-scan base-package="igate.dto" />
<context:component-scan base-package="igate.dao" />
<context:component-scan base-package="igate.service" />
<context:component-scan base-package="igate.controller" />
<context:component-scan base-package="igate.logs" />
<context:component-scan base-package="igate.testcases" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp" />
</bean>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#172.21.17.5:1521:oraten" />
<property name="username" value="lab01trg21" />
<property name="password" value="lab01oracle" />
</bean>
<bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds"/>
</bean>
</beans>
Instead of this code:
#Autowired
template JdbcTemplate;
You need:
#Autowired
JdbcTemplate template;
The bean you try to inject in is not in the spring context;
No setter for the JdbcTemplate
You try to use the template in the constructor before the template is injeted
One reason for this error is to mix autowiring with manual
creation of beans.
For instance, you have a service class that autowires a bean.
#Service
public class CarService {
#Autowired
public JdbcTemplate jdbcTemplate;
// service code
}
But later intead of
#Autowired
private CarService carService;
you do:
CarService carService = new CarService();

Resources