开发者

Annotation based transactions not working - spring 3

开发者 https://www.devze.com 2023-04-06 02:04 出处:网络
I am trying to integrate hibernate into my first Spring web-project using annotation-based transactions. However, this does not work, as I notice on a save query not committing.

I am trying to integrate hibernate into my first Spring web-project using annotation-based transactions. However, this does not work, as I notice on a save query not committing.

This is the aop configuration:

<context:annotation-config />
<context:component-scan base-package="package.names.project.controller" />
<context:component-scan base-package="package.names.project.model" />
<context:component-scan base-package="package.names.common.util" />

<aop:aspectj-autoproxy>
    <aop:include name="Logger" />
</aop:aspectj-autoproxy>

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean 
    below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <!-- the transactional semantics... -->
    <tx:attributes>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="save" read-only="false"/>
        <tx:method name="*" rollback-for="Exception" />
    </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution of 
    an operation defined by a service in the service package -->
<aop:config>
    <aop:pointcut id="serviceOperations" expression="execution(* package.names.project.dao.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperations" />
</aop:config>

<!-- similarly, don't forget the PlatformTransactionManager -->
<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>


<bean id="L开发者_如何学JAVAogger" class="package.names.common.aop.Logger" />
<tx:annotation-driven transaction-manager="txManager" />

I have the following hibernate configuration:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
    <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
    <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/db</property>
    <property name="hibernate.connection.username">user</property>
    <property name="connection.password">pass</property>
    <property name="connection.pool_size">1</property>
    <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
    <property name="show_sql">true</property>
    <property name="hbm2ddl.auto">update</property>
            <property name="connection.autocommit">true</property> 

    <mapping class="package.names.model.Person" />
</session-factory>
</hibernate-configuration>

Bean declarations:

<bean id="personDao" class="package.names.project.dao.PersonDaoImpl"></bean>
<bean id="dbService" class="package.names.project.service.DbService"></bean>

My service layer looks like this

@Service("Service")

public class DbService {
    @Autowired
    private PersonDao personDao;

    public void setPersonDao(PersonDao personDao){
        this.personDao=personDao;
    }

    @Transactional(readOnly = false)
    public void save(Person person){
        personDao.save(person.getName(), person.getAge());
    }
    @Transactional
    public List<String> listPerson(){
        return personDao.listPerson();
    }
}

Changed the sessionFactory in my dao to an autowired one:

public class PersonDaoImpl implements PersonDao {
    @Autowired
    SessionFactory factory;

    public void setFactory(SessionFactory factory){
        this.factory = factory;
    }

    public Long save(String personName, Integer personAge) {
        Long personId = null;
        Session session = factory.openSession();
        System.out.println( TransactionSynchronizationManager.isActualTransactionActive());
        Person person = new Person();
        person.setName(personName);
        person.setAge(personAge);
        session.saveOrUpdate(person);
        session.close();
        return personId;
    }..

There are just no signs the transactions are committed. (No insert statements are shown while show-sql is true) There are no error messages to clearify it.

(if I add 'session.beginTransaction().commit()' to my save() function, it will work. But that seems against the principles of declarative transaction management.)

UPDATE:

The database connection works fine, as does the listPerson() method.

I can confirm transaction is active in the save method and that the save method is used by using

logger.info(TransactionSynchronizationManager.isActualTransactionActive())

And I can see autocommitting is set to true in the logging:

INFO: autocommit mode: true

I even created a service layer between the controller and the dao, to be sure it's not the dao layer causing problems. I used

@Transactional(readOnly = false)

to be sure the problem wasn't caused by a read-only mode. What's left to try?

UPDATE 2: Fixed the problem. It was caused by opening a new session each time the method save was called. Now I just use factory.openSession() one time, after that I use factory.getCurrentSession() and I don't close the session.


The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup.

Since your exception is complaining about eager-loading try adding lazy-init="true" attribute to your Spring beans.

Example:

<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager" lazy-init="true">
    <property name="sessionFactory" ref="mySessionFactory" />
</bean>

For more information on Lazy initialization see.

EDIT

Also to resolve your commit issue, try adding below to your datasource settings:

<property name="defaultAutoCommit" value="true" />


To use @Transactional your bean must be accessed via Spring container. In provided sample I don't see anything that would show how this bean is created. You must have either

<context:component-scan base-package="package.names"/>

or

<bean class="package.names.PersonDaoImpl"/>

And then you would have to get bean from container either via autowiring or getBean().

So how do you get your DAO bean instance in the application? Also it would be helpful to see bean class declaration as well as interface. I did have cases when transactional proxies are not properly created because of some specifc class relationships.

0

精彩评论

暂无评论...
验证码 换一张
取 消