Spring + Hibernate + JPA + 2 databases. persist silently fails to commits with #Transactional annotation - spring

My setup is Spring MVC 3.1, Hibernate 4.1 with two databases.
My service methods seem to work fine for reads (for both dbs). But the persist fails to insert the data in the db - and no exception in the logs at all. Looking at the sql output of hibernate it looks like it did retrieve the newly generated id but then never did the insert - if it did it doesn't show in the db nor was an insert logged in the log file. In the db I can see the sequence number is incremented but no data was inserted. I couldn't figure out what is wrong with my config. Hopefully someone has an idea.
Below are the relevant pieces from config file
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
</bean>
<bean id="mgrFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource">
<property name="packagesToScan" value="xxx.yyy" />
<property name="persistenceUnitName" value="puOne"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
</property>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="txMgr"/>
<bean id="txMgr"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="mgrFactory">
</bean>
This works fine as it is. What I want to do now is add the ability to use another database. So I added another data source, entity manager factory and transaction manager
<bean id="dataSourceTwo" class="org.apache.commons.dbcp.BasicDataSource">
</bean>
<bean id="mgrFactoryTwo"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSourceTwo">
<property name="packagesToScan" value="xxx.zzz" />
<property name="persistenceUnitName" value="puTwo"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
</property>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="txMgrTwo"/>
<bean id="txMgrTwo"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="mgrFactoryTwo">
</bean>
I also made sure that the two respective base DAOs annotate their entity manager's with the unit name like
#PersistenceContext(unitName = "puOne")
protected EntityManager entityManager;
The last thing I did was to add the transaction manager names inside my #Transactional annotations inside my services like
#Override
#Transactional(value="txMgrTwo" propagation = Propagation.REQUIRED)
public boolean create(User user) {
userDao.persist(user);
}

Related

Data is not getting inserted in JPA Spring weblogic

I have following configuration in application context
<jee:jndi-lookup id="dataSource" jndi-name="MY_DS" />
<context:load-time-weaver/>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="persistenceUnitName" value="pu_TEST" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
Now my DAO Class
#Repository
public class EmployeeDAO{
#PersistenceContext
private EntityManager em;
#Transactional
public void create(Employee entity) {
LOG.error("Enitity Manager:create" + em);
em.persist(entity);
// em.flush(); if i use flush it saves
}
}
Now when I save the entity it does not say give any error but no data is updated into db.
I do not wish to use flush as entitymanager is injected by spring and should perform flush at the end automatically which is not happening. correct my understanding.
Adding facade class may be issue is there, Does Propagation.REQUIRES_NEW has anything to do here?
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void process(){
Employee e = factory.getEmployee();
employeeDao.create(e);
}
On Debug after create method call it shows employee got primary key populated that mean db call has made but at the end it is not persisted.
Please try either of the 3 :
1.Solution 1
Please call below code
em.joinTransaction();
just before
em.persistEntity(entity);
2.Solution 2
make attribute readOnly=false in #Transactional
3.Solution 3
Try manually adding bean EmployeeDAO in spring xml file
or else you can try below:
#Transactional(propagation=Propagation.REQUIRED)

Should I use beginTransaction while using #Transactional?

I am quite confused with Spring and Hibernate transactions. I have the following sample code.
I am wondering if
This is a correct way of retrieval or not.
Should I use getCurrentSession().beginTransaction() as well, should I use it in conjunction with #Transactional at all?
Configuration
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:2000/HiberProject" />
<property name="username" value="jack" />
<property name="password" value="jack" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
depends-on="dataSource">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.hiberproject.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Service
#Service
public class SampleRecordsServiceImpl implements SampleRecordsService{
#Autowired
SampleRecordsRepository sampleRecordsRepository;
#Override
#Transactional(readOnly=true)
public Record retrieveRecord(long id){
return sampleRecordsRepository.retrieveRecord(id);
}
}
Repository
#Repository
public class SampleRecordsRepository implements SampleRecordsRepository{
#Autowired
SessionFactory sessioFactory;
#Override
public Record retrieveRecord(long id){
return (Record) sessionFactory.getCurrentSession().get(Record.class,id);
}
}
The #Transactional annotation itself defines the scope of a single database transaction. The database transaction happens inside the scope of a persistence context.
The persistence context is just a synchronizer object that tracks the state of a limited set of Java objects and makes sure that changes on those objects are eventually persisted back into the database.
For #Transactional annotation you can set propagation attribute, using Propagation you can handle your tarnsaction in different way like Propagation.REQUIRES_NEW(if you need new transaction on every request) . the default propagation is REQUIRED.
session.beginTransaction() will also either begin a new Transaction if one isn't present, or it will use an existing transaction to begin the unit of work specified.
So you should use either one of approach to manage the transaction.
Yes that's Okay to use only #Transactional annotation like this when you use Spring to manage your transaction.
No. You don't need to do that! If you use #Transactional annotation in your service, then Spring takes care of your persistence layer to manage transaction. All you need is to declare persistence layer specific transaction manager in your Spring configuration. So you do not need to manage transaction with hibernate sessions by using session.beginTransaction() together with #Transactional.
For more information please see the documentation of using #Transactional.

We want to get all the records in Database using HQL in terms of Spring and Hibernate

Here i tried 2 write cod 2 get list from Mysql Database using spring nd Hibernate.
But problem is here that how initialize **org.hibernate.Session se through "applicationContext.xml" file by bean class....
public void getList(**Session se**){
String liststudent="from StudentList stud";
Query q=se.createQuery(liststudent);
List<Object> list=q.list();
for(Object obj:list){
Object studarr[]=(Object[])obj;
System.out.println("Data at Zero Index"+studarr[0]);
}
}
As here property name **template** has been initialized by the ref template.
Is there any way to initialize Session se.
<bean name="mydao" class="dao.MyDao">
<property name="template" ref="template"></property>
</bean>
using your context.xml file
define sessionFactory
<bean id="sessionFactory" class="LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--define other properties...mapping files
</bean>
define hibernateTemplate
<bean id="template" class="*HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
then
<bean name="mydao" class="dao.MyDao">
<property name="template" ref="template"></property>
</bean>
NOTE: the class package has been ommitted

integration tests via spring, hsqldb doesn't recognize "use index"

I have a spring project with the dao and integration tests for it. For integration tests I am using hsqldb.
Everything was ok, untill I had to add "USE INDEX" command to my query. The application works fine and fetches records as expected.
But tests started to faile with SQL exception "Unexpeced token USE in command".
So I am wondering, is there any way to configure htsqldb to recognize "USE INDEX" statement? Thanks
My Dao looks like the following:
public interface SomeDao extends CrudRepository<Mapping, Integer> {
#Query(value = "SELECT mm.record_id" +
" FROM mappings mm" +
" USE INDEX (mapping_indx)" +
" JOIN records ss ON mm.record_id = ss.id "
" WHERE mm.name= :name", nativeQuery = true)
public List<Integer> getRecordsIds(#Param("name") String name);
}
My test example:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath*:testContext.xml")
public class SimpleTEst{
#Autowired
private SomeDao someDao;
//...other daos
#Test
public void testDao() {
//...test background creation
List<Integer> actualList = someDao.getRecordsIds("testing");
assertEquals(expectedList, actualList);
}
}
testContext.xml contains the following settings
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:myTest"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaDialect" ref="jpaDialect"/>
<property name="persistenceXmlLocation" value="classpath*:/META-INF/persistence.xml"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="namingStrategy" class="org.hibernate.cfg.ImprovedNamingStrategy"/>
different dbs are not compatible so, in general, you can't run same sql on both of them. you have a few quick potential workarounds:
teach your test database new constructs/functions. in some in-memory dbs you can register new functions. not sure if it's your case
skip some tests when running on different-vendor-db. if you don't test also on same-vendor-db then this actually mean: remove the test :(
create/choose query dynamically base on your runtime-detected vendor. this way you can limit tested part of query
to summarize: there is probably absolutely no way to test use index on hsqldb. you should test it on real db. if you really want to stick to hsqldb, what you can do is to try to test as similar query as possible... but not the same, sorry

Spring JUnit JPA Transaction not rolling back

I am trying to test my DAO that uses JPA EntityManager to fetch and update entities. I have marked my unit test as Transactional and set the defaultRollback property to false. However, I don't see my transactions rolling back at the end of the test when throwing a rune time exception. The data is getting persisted in the DB. Here is my unit test code along with spring configuration. I am clearly missing something but havent been able to identify what.
Btw, the transaction is RESOURCE_LOCAL in the persistence.xml
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:spring/test-jpa.xml"})
#TestExecutionListeners(
{ DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class
})
#TransactionConfiguration(defaultRollback=false)
#Transactional
public class JpaTests {
#PersistenceContext
EntityManage em;
#Test
public void testTransactionQueueManager() {
Object entity = em.find(1);
//code to update entity omitted.
entity = em.merge(entity);
em.flush();
throw new RuntimeException
}
}
Spring Configuration
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jpa.driverclassname}" />
<property name="url" value="${jpa.url}" />
<property name="username" value="${jpa.username}" />
<property name="password" value="${jpa.password}" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="${jpa.persistenceunitname}"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
<property name="databasePlatform" value="org.apache.openjpa.jdbc.sql.DBDictionary"/>
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
Your configuration seems fine.
There could be different reasons for the unexpected commit, maybe a datasource with autocommit mode or a non transaction compliant database (mysql with MyISAM ?)
Did you check this thread Why are transactions not rolling back when using SpringJUnit4ClassRunner/MySQL/Spring/Hibernate ?
#TransactionConfiguration(defaultRollback=false)
might be the culprit. Try defaultRollback=true, that should rollback the transaction.
Adding rollbackFor may help, it's a common pitfall.
#Transactional(rollbackFor=Exception.class)

Resources