基于注释的交易无效 - 春季3

时间:2011-09-19 14:40:41

标签: hibernate spring transactions annotations

我正在尝试使用基于注释的事务将hibernate集成到我的第一个Spring Web项目中。但是,这不起作用,因为我注意到保存查询没有提交。

这是aop配置:

<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="Logger" class="package.names.common.aop.Logger" />
<tx:annotation-driven transaction-manager="txManager" />

我有以下hibernate配置:

<?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声明:

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

我的服务层看起来像这样

@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();
    }
}

将我的dao中的sessionFactory更改为自动装配的:

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;
    }..

没有迹象表明交易已经提交。 (当show-sql为true时,不显示插入语句)没有错误消息可以清除它。

(如果我将'session.beginTransaction()。commit()'添加到我的save()函数中,它将起作用。但这似乎违反了声明式事务管理的原则。)

更新

数据库连接工作正常,listPerson()方法也是如此。

我可以在save方法中确认事务处于活动状态,并且使用

来使用save方法
logger.info(TransactionSynchronizationManager.isActualTransactionActive())

我可以看到在日志记录中将autocommitting设置为true:

INFO: autocommit mode: true

我甚至在控制器和dao之间创建了一个服务层,以确保它不是导致问题的dao层。我用了

@Transactional(readOnly = false)

确保问题不是由只读模式引起的。 还有什么可以尝试的?

更新2: 解决了这个问题。这是因为每次调用方法保存时都会打开一个新会话。现在我只使用factory.openSession()一次,然后我使用factory.getCurrentSession()并且我不关闭会话。

2 个答案:

答案 0 :(得分:1)

  

ApplicationContext实现的默认行为是   在启动时急切地预先实例化所有单例bean。

由于您的异常是抱怨急切加载,请尝试向您的Spring bean添加lazy-init="true"属性。

示例:

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

有关延迟初始化 see的更多信息。

修改

另外,要解决您的提交问题,请尝试在下面添加datasource设置:

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

答案 1 :(得分:1)

要使用@Transactional,必须通过Spring容器访问您的bean。在提供的示例中,我没有看到任何可以显示如何创建此bean的内容。你必须有

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

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

然后你必须通过自动装配或getBean()从容器中获取bean。

那么如何在应用程序中获取DAO bean实例?另外,查看bean类声明以及接口会很有帮助。我确实遇到了由于某些特定的类关系而没有正确创建事务代理的情况。