有一个具有以下配置的简单 Spring-Hibernate 应用程序:
应用程序上下文:
<context:component-scan base-package="org.hibtests" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>org.hibtests.domain.Person</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/hibernatedb" />
<property name="username" value="dbuser" />
<property name="password" value="blahblah" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
主应用程序如下所示
ApplicationContext context = new ClassPathXmlApplicationContext("simpleappcontext.xml");
PersonService personService = (PersonService) context.getBean("personService");
Person person = new Person();
person.setName("Alba");
person.setEmail("alba@gmail.com");
personService.addPerson(person);
PersonService
被注释为 @Transactional
:
package org.hibtests.service;
@Transactional
@Component
public class PersonService {
@Autowired
private PersonDao personDao;
public PersonDao getPersonDao() {
return personDao;
}
@Transactional(readOnly=false)
public void addPerson(Person person) {
getPersonDao().insert(person);
}
}
PersonDao.java:
package org.hibtests.dao;
@Repository
public class PersonDao {
@Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void insert(Person person) {
Session session = getSessionFactory().getCurrentSession();
session.persist(person);
}
产生错误
INFO: Using DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource@1fe4169] of Hibernate SessionFactory for HibernateTransactionManager
Exception in thread "main" org.hibernate.HibernateException: persist is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:348)
at $Proxy16.persist(Unknown Source)
at org.hibtests.dao.PersonDao.insert(PersonDao.java:26)
at org.hibtests.dao.PersonService.addPerson(PersonService.java:27)
at org.hibtests.dao.PersonService$$FastClassByCGLIB$$403bca40.invoke(<generated>)
虽然我可以在 persist
方法之前和之后使用 session.beginTransaction()
和 session.getTransaction().commit()
,是否可以只使用 Spring 的 @Transactional 注解来管理事务?如果是这样怎么办?
最佳答案
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
您自己的配置破坏了正确的事务支持/集成。当使用 Spring 进行声明式事务管理时,切勿混淆 hibernate.current_session_context_class 属性。除非您使用 JTA,否则您需要将其与 JTA 集成。
Spring 默认情况下会注册自己的 CurrentSessionContext
实现,以便与 hibernate 进行正确的事务集成。它将注册SpringSessionContext
。然而,一旦您开始配置 hibernate.current_session_context_class ,此默认值将被覆盖,因此事务会中断。
从您的配置中删除该行。
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
这将正确地让 spring 注册它自己的上下文 session 管理。
关于java - 如何使用 Spring 中的 @Transactional 保存实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21381186/