@Transactional 与 JPA 和 Hibernate 有啥用?

Posted

技术标签:

【中文标题】@Transactional 与 JPA 和 Hibernate 有啥用?【英文标题】:What is the use of @Transactional with JPA and Hibernate?@Transactional 与 JPA 和 Hibernate 有什么用? 【发布时间】:2019-06-16 23:42:48 【问题描述】:

我正在学习如何使用 JPA 和 Hibernate 以及 mysql 数据库创建 REST API,我看到了这个 @Transactional 注释。有人可以解释这个注释的用途吗?

例如我有这个简单的 DAO 类:

@Repository
public class EmployeeDAOHibernateImpl implements EmployeeDAO 

    // define field for entitymanager
    private EntityManager entityManager;

    // set up constructor injection
    @Autowired
    public EmployeeDAOHibernateImpl(EntityManager entityManager) 
        this.entityManager = entityManager;
    

    @Override
    @Transactional
    public List<Employee> findAll() 

        // get the current hibernate session
        Session currentSession = entityManager.unwrap(Session.class);

        // create a query
        Query<Employee> theQuery = 
                currentSession.createQuery("from Employee", Employee.class);

        // execute query and get result list
        List<Employee> employees = theQuery.getResultList();

        // return the results
        return employees;
    


您可以看到用于 findAll() 方法的@Transactional,但是如果我删除这个@Transactional 我会得到相同的输出...那么这个@Transactional 有什么用?

【问题讨论】:

Spring - @Transactional - What happens in background?的可能重复 这与 JPA ... FWIW 无关。那是春天 【参考方案1】:

@Transactional 注释用于当您希望某个方法/类(=内部的所有方法)在事务中执行时。

假设用户 A 想要将 100 美元转给用户 B。会发生什么:

    我们将 A 的账户减少 100 美元 我们向 B 的帐户添加 100 美元

假设在成功1) 之后和执行2) 之前抛出异常。现在我们会出现某种不一致,因为A 损失了 100 美元,而B 一无所获。 交易意味着全部或全部。如果方法中某处抛出异常,则更改不会持久保存在数据库中。发生了名为rollback 的事情。

如果您不指定@Transactional,每个数据库调用将在不同的事务中。

【讨论】:

一个不错的答案,但应该添加一件事 - 如果示例代码 @Transactional 是不必要的,也许它是“迷信编程”,有人总是添加 @Transactional 即使它没有效果“只是万一”:)【参考方案2】:

一般@Transactional注解写在服务层。

它用于将多个写入在数据库上作为单个原子操作

当有人调用带有@Transactional 注释的方法时数据库上的所有或没有写入被执行

在读取操作的情况下它没有用,因此在单个原子写入的情况下也是如此。您在单次读取(选择)中使用它,因此添加或删除 @Transactional 注释没有影响。

【讨论】:

在读取操作中,如果使用 Java Streams 来放置选择结果会很有用... 值得补充的是,当对处于persistent 状态(由实体管理器管理)的实体进行多次更新时,应使用@Transactional,因此save() 不能显式放入代码,但设置器在实体上调用 @viruskimera 你能详细说明或提供一些链接吗?【参考方案3】:

该类在其自身或其成员上声明@Transactional,Spring 创建一个代理,该代理实现与您正在注释的类相同的接口。换句话说,Spring 将 bean 包装在代理中,而 bean 本身不知道它

代理为 Spring 提供了一种在方法调用之前、之后或周围将行为注入被代理对象的方法。

在内部,它与使用事务通知(使用 AOP)相同,其中首先创建代理并在目标 bean 的方法之前/之后调用。

生成的代理对象由 Spring 创建的 TransactionInterceptor 提供。因此,当从客户端代码调用@Transactional 方法时,首先从代理对象调用TransactionInterceptor,代理对象开始事务并最终调用目标bean 上的方法。当调用完成时,TransactionInterceptor 相应地提交/回滚事务

【讨论】:

以上是关于@Transactional 与 JPA 和 Hibernate 有啥用?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 和 Spring Data JPA @Transactional 不工作

如何处理来自catch块的spring jpa @transactional和新插入[重复]

事务管理配置与@Transactional注解使用

Spring Data JPA @Modifying 注解使用@Transactional

JPA中自定义的插入更新删除方法为什么要添加@Modifying注解和@Transactional注解?

SpringBoot JPA 在@Transactional 上不需要 .save() 吗? [复制]