基于注释的事务不起作用 - spring 3
我正在尝试使用基于注释的事务将 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() 方法也是如此。
我可以确认保存方法中的事务处于活动状态,并且通过使用使用保存方法
logger.info(TransactionSynchronizationManager.isActualTransactionActive())
并且我可以在日志记录中看到自动提交设置为 true:
INFO: autocommit mode: true
我什至在控制器和 dao 之间创建了一个服务层,以确保它不是dao 层造成问题。我曾经
@Transactional(readOnly = false)
确信问题不是由只读模式引起的。 还需要尝试什么?
更新2: 解决了这个问题。这是由于每次调用 save 方法时打开一个新会话造成的。现在我只使用factory.openSession()一次,之后我使用factory.getCurrentSession()并且不关闭会话。
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="Logger" 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于您的异常抱怨急切加载,请尝试向 Spring bean 添加
lazy-init="true"
属性。示例:
有关延迟初始化的更多信息参见。
编辑
另外,为了解决您的提交问题,请尝试将以下内容添加到您的
数据源
设置中:Since your exception is complaining about eager-loading try adding
lazy-init="true"
attribute to your Spring beans.Example:
For more information on Lazy initialization see.
EDIT
Also to resolve your commit issue, try adding below to your
datasource
settings:要使用@Transactional,您的bean必须通过Spring容器访问。在提供的示例中,我没有看到任何可以显示该 bean 是如何创建的内容。您必须有
或
然后您必须通过自动装配或 getBean() 从容器获取 bean。
那么如何在应用程序中获取 DAO bean 实例呢?此外,查看 bean 类声明和接口也会很有帮助。我确实遇到过由于某些特定的类关系而未正确创建事务代理的情况。
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 eitheror
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.