Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure Spring to make JPA (Hibernate) and JDBC (JdbcTemplate or MyBatis) share the same transaction

I have a single dataSource, I use Spring 3.0.3, Hibernate 3.5.1 as JPA provider and I use MyBatis 3.0.2 for some queries and my app runs on Tomcat 6. I have a HibernateDAO and a MyBatisDAO, when I call both from the same method which is annotated with @Transactional it looks like they don't share the same transaction, they get different connections.
How can I make them to do?

I've tried getting a connection from DataSourceUtils.getConnection(dataSource) and I get the one which is used by MyBatis which is strange I thought the problem was in MyBatis config and it can't use JpaTransactionManager. Even calling multiple times DataSoruceUtils.getConnection gives the same connection always, which is ok.

After some googling I've tried spring-instrument-tomcat's classloader (although I don't know if tomcat really uses it :))

partial applicationContext

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">     <property name="driverClassName" value="${database.driverClassName}"/>     <property name="url" value="${database.url}"/>     <property name="username" value="${database.username}"/>     <property name="password" value="${database.password}"/> </bean>  <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">     <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean>  <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>  <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">     <property name="dataSource" ref="dataSource"/> </bean>  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">     <property name="dataSource" ref="dataSource" />     <property name="configLocation" value="classpath:META-INF/mybatis/mybatis-config.xml" /> </bean> 

partial mybatis config

<settings>     <setting name="cacheEnabled" value="false" />     <setting name="useGeneratedKeys" value="false" />     <setting name="defaultExecutorType" value="REUSE" />     <setting name="lazyLoadingEnabled" value="false"/> </settings> 

partial persistence.xml

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> 
like image 436
tewe Avatar asked Jul 21 '11 14:07

tewe


People also ask

Can we use both JDBC and JPA together?

JPA-based applications still use JDBC under the hood. Therefore, when we utilize JPA, our code is actually using the JDBC APIs for all database interactions. In other words, JPA serves as a layer of abstraction that hides the low-level JDBC calls from the developer, making database programming considerably easier.

Can we use JDBCTemplate with transactional?

It loops through the list of people and, for each person, inserts that person into the BOOKINGS table by using the JdbcTemplate . This method is tagged with @Transactional , meaning that any failure causes the entire operation to roll back to its previous state and to re-throw the original exception.

Is JDBCTemplate faster than JPA?

At work we use Hibernate JDBCTemplate because it has more flexibility. It also has better performance than JPA because you are not "loading" a lot of unnecessary data into your app. In the JDBCTemplate case, your SQL skills go a long way in giving you exactly what you need at the right speed.

Can we use JDBCTemplate with hibernate?

In our project, we are using both, JdbcTemplate and Hibernate . What you need to do is share DataSource between hibernate and jdbcTemplate . We can check performance for both according to operations, whichever is better, we use better one.


1 Answers

I've found the solution here: What transaction manager should I use for JBDC template When using JPA ?

I'm using JpaTransactionManager and not DataSourceTransactionManager.
JavaDoc http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html

This transaction manager also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access JPA and services which use plain JDBC (without being aware of JPA)! Application code needs to stick to the same simple Connection lookup pattern as with DataSourceTransactionManager (i.e. DataSourceUtils.getConnection(javax.sql.DataSource) or going through a TransactionAwareDataSourceProxy). Note that this requires a vendor-specific JpaDialect to be configured.

After I've added jpaVendorAdapter to my entityManagerFactory config everything works, both JdbcTemplate query and MyBatis runs in the same transaction as expected. Based on the JavaDoc I guess a jpaDialect should be enough but it's 4 a.m. here so I won't try that now :)

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">     <property name="persistenceUnitName" value="persistenceUnit"/>     <property name="dataSource" ref="dataSource"/>     <property name="jpaVendorAdapter">         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">             <property name="showSql" value="true" />             <property name="generateDdl" value="true" />             <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />         </bean>     </property> </bean> 
like image 183
tewe Avatar answered Oct 16 '22 02:10

tewe