How to execute several sql-statements in one session with mybatis-string - java

I am setting up an application with mybatis-spring, which should execute several sql-statements (mostly selects) and print the result to the console.
My applicationContext.xml looks like this:
<context:property-placeholder location="classpath:application.properties"/>
<!-- BEANS -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${spring.datasource.driverClassName}"/>
<property name="url" value="${spring.datasource.url}"/>
<property name="username" value="${spring.datasource.username}"/>
<property name="password" value="${spring.datasource.password}"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:sql_mapper.xml"/>
</bean>
<bean id="organisationMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="mapper.OrganisationMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
I have noticed that whenever I execute a sql-statement the session is created just for this statement and closes directly after execution.
Is there a way to execute multiple sql-statements in just one session, which closes itself not until all methods/statements are executed?
Thanks and Greetings.

It seems that transactions are not demarcated properly and the default behaviour (one call to mapper - one transaction - one mybatis session) is used.
In spring-mybatis the session bound to spring transaction. If transactions are not demarcated then a transaction is created (and hence mybatis SqlSession) for every call to mybatis mapper method.
In order to change this you need to properly configure spring so that:
transactions can be used at all
configure transaction boundaries that is what calls to the database should be executed in one transaction
There are many ways to configure transactions for details see documentation. I'll show here the simple way that uses xml configuration.
Firstly, add transaction manager to the spring configuration:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Then you need to specify transactions boundaries. The simple way is to use declarative transaction management:
Add this to spring configuration
<tx:annotation-driven/>
And then use #Transactional annotation on methods that should be executed transactionally:
#Service
class SomeService {
#Autowired MyMapper mapper;
#Transactional
SomeResult someMethod () {
Piece1 piece1 = mapper.getSome();
Piece2 piece2 = mapper.getMore();
SomeResult result = SomeResult(piece1, piece2);
}
}

Related

#Transactional only works in DAO, not in service (No Hibernate Session bound to thread)

I have a service method that calls a DAO method. The service method is annotated as #Transactional, the DAO method is not. At runtime the following error occurs:
No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
When I make the DAO method #Transactional as well, it works fine.
How can I fix this without touching the DAO? (Most methods are in a super-class DAO which I don't have access to.)
I'm using hibernate-core-3.6.8 and spring-orm-4.1.6.RELEASE
The DAOs are annotated as #Repository, the services as #Service
My applicationContext.xml looks like this (I just provided the important parts - let me know if you need more):
<bean id="contextApplicationContextProvider" class="at.spardat.deploysolution.process.context.ApplicationContextProvider"/>
<tx:annotation-driven/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<util:properties id="hibernateProperties" location="classpath:hibernate.properties"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
p:dataSource-ref="dataSource" p:hibernateProperties-ref="hibernateProperties">
<qualifier value="default"/>
<property name="mappingLocations">
<list>
<value>classpath:....hbm.xml</value>
</list>
</property>
<property name="lobHandler" ref="defaultLobHandler"/>
</bean>
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" lazy-init="true"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
<bean id="dataFieldMaxValueIncrementer" class="org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer"
p:dataSource-ref="dataSource" p:incrementerName="TB_OID_SEQUENCE" p:columnName="OID_VALUE">
<qualifier value="default"/>
</bean>
Can you change
hibernate.current_session_context_class=thread
in your hibernate properties file
Thanks

Propagation.REQUIRES_NEW does not create a new transaction in Spring with JPA

I have the following scenario. I am using JPA, Spring:
#Autowired
SampleService service;
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void PerformLogic(LogicData data) throws SIASFaultMessage
{
SampleObject so = createSampleObject();
try{
.//do some logic to persist things in data
.
.
persistData(data);
.
.
.
updateSampleObject(so);
}
catch(Exception){
updateSampleObject(so);
throw new SIASFaultMessage();
}
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public createSampleObject()
{
SampleObject so = new SampleObject();
.
.//initialize so
.
service.persist(so);
return so;
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public updateSampleObject(SampleObject so)
{
service.persist(so);
return so;
}
When everything works fine, data is persisted in database without problems. However, when an exception is thrown, I need that the method updateSampleObject(so) persist the information in the database. This is not what is happening. If an exception is thrown the method updateSampleObject gets rolled back also, which is not what I need. I need that these two methods (createSampleObject and updateSampleObject) get persisted all the time, no matter whether an exception got thrown or not.
How can I achieve this?
Moreover, if I anotate the methods createSampleObject and updateSampleObject with:
#Transactional(propagation = Propagation.NEVER)
the idea is that an exception is thrown and I get no exception thrown. Where is the problem? Analizing the logs I see this line:
org.springframework.orm.jpa.JpaTransactionManager ==> Creating new transaction with name [com.test.PerformLogic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT....
which means this transaction is created, but I see no hint of the other transaction.
This is the part of my configuration file for Spring regarding transactions
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan" value="cu.jpa"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">${hdm2ddl.auto}</prop>
</props>
</property>
<property value="/META-INF/jpa-persistence.xml" name="persistenceXmlLocation"/>
<property name="persistenceUnitName" value="jpaPersistenceUnit"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="nestedTransactionAllowed" value="true" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Spring transactions are proxy-based. Here's thus how it works when bean A causes a transactional of bean B. A has in fact a reference to a proxy, which delegates to the bean B. This proxy is the one which starts and commits/rollbacks the transaction:
A ---> proxy ---> B
In your code, a transactional method of A calls another transactional method of A. So Spring can't intercept the call and start a new transaction. It's a regular method call without any proxy involved.
So, if you want a new transaction to start, the method createSampleObject() should be in another bean, injected into your current bean.
This is explained with more details in the documentation.
My guess is that since both methods are in the same bean, the Spring's AOP does not have a chance to intercept the create/updateSampleObject method calls. Try moving the methods to a separate bean.
Please create a bean for the same class(self) and use bean.api(which requires requires_new).
It works.
In certain cases, even if you have service a -> service b and you have a #Transactional(propagation = Propagation.REQUIRES_NEW) on the service b method(which needs to be public by the way!), locking rows etc may fail.
This is usually if auto-commit: false is not specified in your spring(usually hikari pool) datasource configuration. The reason is that any select for update or similar statements are executed immediately and the database does not lock the row.

EntityManager from LocalContainerEntityManagerFactoryBean does not persist entities into the database

The problem is that the EntityManager injected with #PersistenceContext in a Spring managed bean does not persist the entities to the database. I have tried using #Transactional on the AddDao bean, where entityManager.persist() is called (I have enabled annotation-driven transactions).
The transaction begins in another bean which is instantiated by Camel with .transacted() in the Camel Java DSL. That bean has an #Autowired property which is the DAO and has the EntityManager injected with #PersistenceContext.
As transaction manager Bitronix is used.
A portion of the Spring xml configuration file looks like this:
<bean id="localContainerEntityManagerFactoryBean" depends-on="btmConfig" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="nameFromPersistenceXml"/>
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence"/>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
<property name="packagesToScan" value="package with #Entity POJOs"/>
</bean>
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
</bean>
<!-- create BTM transaction manager -->
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig"
destroy-method="shutdown" />
<!-- Spring JtaTransactionManager -->
<bean id="springTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
</bean>
<tx:annotation-driven transaction-manager="springTransactionManager" />
Edit: In a overly simplified version it looks like this:
In Camel Java DSL there is
from("wsLayer")
.transacted()
.otherProcessing()
.to("bean:addBean?method=addMyEntity")
And add beans look something like this:
#Component
public class AddBean {
#Autowired
private AddDao addDao;
public void addMyEntity(MyEntity myEntity) {
//other business logic
addDao.persistMyEntity(myEntity);
}
}
#Component
public class AddDao {
#PersistenceContext
private EntityManager entityManager;
//I have tried here
//#Transactional and
//#Transactional(propagation = PropagationType.REQUIRES_NEW)
public void persistMyEntity(MyEntity myEntity) {
entityManager.persist(myEntity);
}
}
The reading from the database works well.
See the data source:
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
init-method="init" destroy-method="close">
<property name="uniqueName" value="theName" />
<property name="maxPoolSize" ><value>${db.pool.maxSize}</value></property>
<property name="minPoolSize" ><value>${db.pool.minSize}</value></property>
<property name="allowLocalTransactions" ><value>true</value></property>
<property name="automaticEnlistingEnabled" ><value>true</value></property>
<property name="className" ><value>${db.pool.datasource}</value></property>
<property name="driverProperties" ref="databaseProperties" />
</bean>
where the properties are set in Maven's pom.xml like this:
db.pool.maxSize=15
db.pool.maxSize=5
db.pool.datasource=org.postgresql.xa.PGXADataSource
Did you tried to execute em.flush() after em.persist(entity)?
According with the docs of Java EE:
em.persist(entity): Make an instance managed and persistent.
BUT
em.flush(entity): Synchronize the persistence context to the underlying database.
So, you can do something like:
em.persist(myEntity);
em.flush();
And check if this change make a difference.
From the limited symptoms given, seems like the JTA transaction is not being started and propagated. Your EM would work fine up to a point - reading from DB, allowing data changes against it's Persistent Context cache, but never writing to the DB.
Think it's a config problem and your #Transaction annotations are being ignored.
I have enabled annotation-driven transactions.
Make sure it's configured as follows in your Spring configuration:
<tx:annotation-driven transaction-manager="springTransactionManager"/>
where:
xmlns:tx="http://www.springframework.org/schema/tx"
Try the #Transactional in this way
#Component
public class AddDao {
#PersistenceContext
private EntityManager entityManager;
#Transactional("BitronixTransactionManager")
public void persistMyEntity(MyEntity myEntity) {
entityManager.persist(myEntity);
}
}

Hibernate and JDBC in one transaction

I have a method, marked as #Transactional.
It consists of several functions, one of them uses JDBC and the second one - Hibernate, third - JDBC.
The problem is that changes, made by Hibernate function are not visible in the last functions, that works with JDBC.
#Transactional
void update() {
jdbcUpdate1();
hibernateupdate1();
jdbcUpdate2(); // results of hibernateupdate1() are not visible here
}
All functions are configured to use the same datasource:
<bean id="myDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource" ref="targetDataSource"/>
</bean>
<bean id="targetDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" lazy-init="true" scope="singleton">
<!-- settings here -->
</bean>
myDataSource bean is used in the code. myDataSource.getConnection() is used to work with connections in jdbc functions and
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
...
}
});
is used in hibernate function.
Thanks.
First, avoid using JDBC when using hibernate.
Then, if you really need it, use to Session.doWork(..). If your hibernate version does not yet have this method, obtain the Connection from session.connection().
You can use JDBC and Hibernate in the same transaction if you use the right Spring setup:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="myDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target">
<bean class="MyDaoImpl">
<property name="dataSource" ref="dataSource"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
This assumes that the JDBC portion of your DAO uses JdbcTemplate. If it doesn't you have a few options:
Use DataSourceUtils.getConnection(javax.sql.DataSource) to get a connection
Wrap the DataSource you pass to your DAO (but not necessarily the one you pass to the SessionFactory) with a TransactionAwareDataSourceProxy
The latter is preferred since it hidse the DataSourceUtils.getConnection inside the proxy datasource.
This is of course the XML path, it should be easy to convert this to annotation based.
The problem is, the operations on Hibernate engine does not result in immediate SQL execution. You can trigger it manually calling flush on Hibernate session. Then the changes made in hibernate will be visible to the SQL code within the same transaction. As long as you do DataSourceUtils.getConnection to get SQL connection, because only then you'll have them run in the same transaction...
In the opposite direction, this is more tricky, because you have 1nd level cache (session cache), and possibly also 2nd level cache. With 2nd level cache all changes made to database will be invisible to the Hibernate, if the row is cached, until the cache expires.

What transaction manager should I use for JBDC template When using JPA ?

I am using standard JPA transaction manager for my JPA transactions. However, now I want to add some JDBC entities which will share the same 'datasource'. How can I make the JDBC operations transactional with spring transaction? Do I need to switch to JTA transaction managers? Is it possible to use both JPA & JDBC transactional service with same datasource? Even better, is it possible to mix these two transactions?
UPDATE:
#Espen :
I have a dao extended from SimpleJdbcDaoSupport which uses getSimpleJDBCTemplate.update to insert a database row. When a RuntimeException is thrown from the service code, the transaction never rolls back when using JPATransactionManager. It does rollback when using DatasourceTransactionManager. I tried to debug the JPATransactionManager and seems that it never performs rollback on underlying JDBCConnection(I guess due to the fact that the datasource is not necessarily has to be JDBC for JPA). My configuration setup are exactly like you explained here.
Here are my test codes:
<context:property-placeholder location="classpath:*.properties"/>
<!-- JPA EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation"
value="classpath:/persistence-test.xml" />
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
-->
<!-- Database connection pool -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<property name="testOnBorrow" value="${database.testOnBorrow}" />
<property name="validationQuery" value="${database.validationQuery}" />
<property name="minIdle" value="${database.minIdle}" />
<property name="maxIdle" value="${database.maxIdle}" />
<property name="maxActive" value="${database.maxActive}" />
</bean>
<!-- Initialize the database -->
<!--<bean id="databaseInitializer" class="com.vantage.userGroupManagement.logic.StoreDatabaseLoader">
<property name="dataSource" ref="storeDataSource"/>
</bean>-->
<!-- ANNOTATION SUPPORT -->
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- JPA annotations bean post processor -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<!-- Exception translation bean post processor (based on Repository annotation) -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- throws exception if a required property has not been set -->
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
<bean id="userService" class="com.rfc.example.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
<property name="contactDao" ref="contactDao"></property>
<property name="callRecordingScheduledProgramTriggerDAO" ref="com.rfc.example.dao.CallRecordingScheduledProgramTriggerDAO"></property>
</bean>
<bean id="userDao" class="com.rfc.example.dao.UserDaoJPAImpl" />
<bean id="contactDao" class="com.rfc.example.dao.ContactDaoJPAImpl"></bean>
<bean id="com.rfc.example.dao.CallRecordingScheduledProgramTriggerDAO" class="com.rfc.example.dao.CallRecordingScheduledProgramTriggerDAOJDBCImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
AND HERE IS THE DAO:
#Transactional
public class CallRecordingScheduledProgramTriggerDAOJDBCImpl extends SimpleJdbcDaoSupport implements CallRecordingScheduledProgramTriggerDAO{
private static final Log log = LogFactory.getLog(CallRecordingScheduledProgramTriggerDAOJDBCImpl.class);
#SuppressWarnings("unchecked")
public CallRecordingScheduledProgramTrigger save(
CallRecordingScheduledProgramTrigger entity) {
log.debug("save -> entity: " + entity);
String sql = null;
Map args = new HashMap();
String agentIdsString = getAgentIdsString(entity.getAgentIds());
String insertSQL = "insert into call_recording_scheduled_program_trigger" +
" ( queue_id, queue_id_string, agent_ids_string, caller_names, caller_numbers, trigger_id, note, callcenter_id, creator_id_string, creator_id) " +
" values(:queueId, :queueIdString, :agentIdsString, :callerNames, :callerNumbers, :triggerId, :note, :callcenterId , :creatorIdString, :creatorId )";
args.put("queueId", entity.getQueueId());
args.put("agentIdsString",agentIdsString);
args.put("callerNames", entity.getCallerNames());
args.put("queueIdString", entity.getQueueIdString());
args.put("callerNumbers", entity.getCallerNumbers());
args.put("triggerId", entity.getTriggerId());
args.put("note", entity.getNote());
args.put("callcenterId", entity.getCallcenterId());
args.put("creatorId", entity.getCreatorId());
args.put("creatorIdString", entity.getCreatorIdString());
sql = insertSQL;
getSimpleJdbcTemplate().update(sql, args);
System.out.println("saved: ----------" + entity);
return entity;
}
}
Here is the client code that calls the dao and throws exception (spring service)
#Transactional(propagation=Propagation.REQUIRED)
public void jdbcTransactionTest() {
System.out.println("entity: " );
CallRecordingScheduledProgramTrigger entity = new CallRecordingScheduledProgramTrigger();
entity.setCallcenterId(10L);
entity.setCreatorId(22L);
entity.setCreatorIdString("sajid");
entity.setNote(System.currentTimeMillis() + "");
entity.setQueueId(22);
entity.setQueueIdString("dddd");
String triggerId = "id: " + System.currentTimeMillis();
entity.setTriggerId(triggerId);
callRecordingScheduledProgramTriggerDAO.save(entity);
System.out.println("entity saved with id: " + triggerId );
throw new RuntimeException();
}
NOTE: the code works as expected when using DatasourceTransactionManager
UPDATE - 2:
Ok I have found the root cause of the problem. Thanks to Espen.
My entity manager configuration was like this(copied from spring pet-clinic app):
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation"
value="classpath:/persistence-test.xml" />
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
</bean>
Then I changed it to like this:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation"
value="classpath:/persistence-test.xml" />
<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.MySQL5Dialect" />
</bean>
</property>
</bean>
Now everything seems to be working! Can anyone explain the difference between these two approach ?
It's possible to mix JPA and JDBC code in the same transaction using the JpaTransactionManager.
A snippet from Spring 3's JavaDoc:
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)!
You should be aware though that JPA caches the queries and executes all of them at the end of a transaction. So if you want to persist some data inside a transaction with JPA and then retrieve the data with JDBC, it will not work without explicitely flushing the JPA's persistence context before you attempt to retreive it with JDBC code.
A code example that asserts with JDBC code that the JPA code deleted a row inside a transaction:
#Test
#Transactional
#Rollback(false)
public void testDeleteCoffeeType() {
CoffeeType coffeeType = coffeeTypeDao.findCoffeeType(4L);
final String caffeForte = coffeeType.getName();
coffeeTypeDao.deleteCoffeeType(coffeeType);
entityManager.flush();
int rowsFoundWithCaffeForte = jdbcTemplate
.queryForInt("SELECT COUNT(*) FROM COFFEE_TYPES where NAME = ?",
caffeForte);
assertEquals(0, rowsFoundWithCaffeForte);
}
And if you prefer to use the JpaTemplate class, just replace the entityManager.flush() with jpaTemplate.flush();
In response to Sajids' comment:
With Spring you can configure a transaction manager that supports both JPA and JDBC like this:
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa
.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
and Annotation-Driven version
#Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(emf);
return jpaTransactionManager;
}
In order to make it work, the JDBC queries must be executed with the JdbcTemplate or the SimpleJdbcTemplate class. In your case with the DAO that extends the SimpleJdbcDaoSupport, you should use the getSimpleJdbcTemplate(..) method.
And finally to let two DAO methods participate in the same transaction, call both DAO methods from a service class metho annotated with #Transactional. With the <tx:annotation-driven> element in your config, Spring will handle the transaction for you with the given transaction manager.
On the business layer:
public class ServiceClass {..
#Transactional
public void updateDatabase(..) {
jpaDao.remove(..);
jdbcDao.insert(..);
}
}
Edit 2:
Then something is wrong. It works for me exactly as specified in the Javadoc.
Does your entity manager has a datasource property like my bean below? It will only work as long you're injecting the same datasource into the entity manager and your extended JpaDaoSupport classes.
<bean id="entityManagerFactoryWithExternalDataSoure" primary="true"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor
.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<value>
hibernate.format_sql=true
</value>
</property>
</bean>
I've not really worked this out in detail yet as I've not mixed both JDBC and JPA but if you get your JDBC connection for an XA datasource then they are JTA transaction. So if you run your code in Stateless session bean for example with transaction turned on, then you automatically get both your Entities and JDBC managed by JTA.
EDIT
Here is an example code from Servlet
private #Resource DataSource xaDatasource;
private #Resource UserTransaction utx;
private #PersistenceUnit EntityManagerFactory factory;
public void doGet(HttpServletRequest req, HttpServletResponse res) ... {
utx.begin();
//Everything below this will be in JTA
Connection conn = xaDatasource.getConnection();
EntityManager mgr = factory.createEntityManager();
//Do your stuff
...
utx.commit();
}
Disclaimer: Code not tested.
Just realize this is not Spring but I'll leave it up anyway

Categories

Resources