java - 如何使用 Spring 中的 @Transactional 保存实体

标签 java spring hibernate transactions

有一个具有以下配置的简单 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/

相关文章:

java - 如何使用 jMockit 模拟 native 方法

java - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) FormParameter 为空

java - 如何定期更改 Canvas 对象的颜色?

java - 将 Java 日期转换为另一种时间作为日期格式

javascript - Spring Boot Ajax 动态填充选择选项

java - @OneToMany 没有反向关系且没有连接表?

spring - 我需要为哪些实体创建 Spring Data 存储库?

spring - Project Lombok @Slf4j 外部配置

java - 使用注释左加入 hibernate

Java Hibernate 表映射