Kaushik Lele
Kaushik Lele

Reputation: 6637

Spring + HibernateTemplate + AOP for transaction mamangement not working

I am using simple "helloWorld"ish application to learn Spring,Hibernate and transaction management using AOP. But is not working as expected. I am getting exception in transaction management. Details as follows :-

Spring version 4.3.8
Hibernate version 5.2.10
HSQL DB version 2.3.4 

Spring.xml look as follows

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<!-- Enable Annotation based Declarative Transaction Management -->
<tx:annotation-driven proxy-target-class="true" mode="aspectj"
    transaction-manager="transactionManager" />

<!-- THIS IS COMMENTED. Without commenting same result. I TRIED USING HibernateTransactionManager. still got same result.  -->
    <!--
<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean> -->


<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
    <property name="url" value="jdbc:hsqldb:file:C:/ProjectRelated/softwares/hsqldb-2.3.4/hsqldb/data/FirstFile"/>
    <property name="username" value="sa"/>
    <property name="password" value="sys"/>
</bean>

<bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" >
    <array>
        <value>com.kaushik.winnersoft.data</value>
    </array>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
        </props>
    </property>
</bean>

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
    <property name="sessionFactory" ref="mySessionFactory"/>
</bean>


<bean id="customerDAO" class="com.kaushik.winnersoft.dao.CustomerDAOImpl">
    <property name="hibernateTemplate" ref="hibernateTemplate"></property>
</bean>

<bean id="customerManager" class="com.kaushik.winnersoft.CustomerManagerImpl">
    <property name="customerDAO" ref="customerDAO"></property>
</bean>

DAOImpl class is

public class CustomerDAOImpl implements CustomerDAO {

private HibernateTemplate hibernateTemplate;

public HibernateTemplate getHibernateTemplate() {
    return hibernateTemplate;
}

public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
    this.hibernateTemplate = hibernateTemplate;
}

@Override
@Transactional
public void create(Customer customer) {
    System.out.println("in  dao creating");
    hibernateTemplate.save(customer);
    System.out.println("in  dao creating done");
}

I get output as follows

Doing
in  dao creating
Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
at org.springframework.orm.hibernate5.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1165)
at org.springframework.orm.hibernate5.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:643)
at org.springframework.orm.hibernate5.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:640)
at org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:359)
at org.springframework.orm.hibernate5.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:326)
at org.springframework.orm.hibernate5.HibernateTemplate.save(HibernateTemplate.java:640)
at com.kaushik.winnersoft.dao.CustomerDAOImpl.create(CustomerDAOImpl.java:27)
at com.kaushik.winnersoft.CustomerManagerImpl.createCustomer(CustomerManagerImpl.java:20)
at com.kaushik.winnersoft.SpringTest.main(SpringTest.java:14)

Answer

Based on the coments given below by M. Denium; I did following changes and it worked.

1) Used HibernateTransactionManager instead of DataSourceTransactionManager

<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="mySessionFactory" />
</bean> 

2) In removed mode="aspectj" so it looks like

<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" />

Upvotes: 2

Views: 1201

Answers (1)

M. Deinum
M. Deinum

Reputation: 125178

I see to problems with your configuration

  1. You are not using the proper PlatformTransactionManager
  2. Unless you are using load- or compile time weaving I doubt the mode="aspectj" is really correct.

First you need to use the PlatformTransactionManager that supports your persistence technology, as you are using Hibernate 5, you need to use the org.springframework.orm.hibernate5.HibernateTransactionManager instead of the DataSourceTransactionManager. (the latter is for application that only do plain JDBC transactions).

From the <tx:annotation-driven /> remove the mode="aspectj" as I suspect you are actually not using full blown AspectJ but are relying on plain Spring to do this for you.

Pro Tip: Instead of using HibernateTemplate, which isn't recommended anymore since Hibernate 3.0.1, just use plain SessionFactory with getCurrentSession instead. This will allow you to write plain Hibernate daos. As suggested in the reference guide.

Upvotes: 2

Related Questions