网站制作推广方案,高端定制手机网站,自己的网站发文章怎么做外链,合肥seo外包平台在本文中#xff0c;我们将深入探讨Spring事务管理。 我们将讨论Transactional在Transactional如何真正工作。 其他即将发布的帖子将包括#xff1a; 如何使用传播和隔离等功能 主要陷阱是什么以及如何避免它们 JPA和事务管理 重要的是要注意#xff0c;JPA本身不提供任何… 在本文中我们将深入探讨Spring事务管理。 我们将讨论Transactional在Transactional如何真正工作。 其他即将发布的帖子将包括 如何使用传播和隔离等功能 主要陷阱是什么以及如何避免它们 JPA和事务管理 重要的是要注意JPA本身不提供任何类型的声明式事务管理。 在依赖项注入容器之外使用JPA时开发人员需要以编程方式处理事务 UserTransaction utx entityManager.getTransaction(); try { utx.begin(); businessLogic();utx.commit(); } catch(Exception ex) { utx.rollback(); throw ex; } 这种管理事务的方式使代码中的事务范围非常清楚但是有一些缺点 它是重复性的并且容易出错 任何错误都会产生很大的影响 错误很难调试和重现 这降低了代码库的可读性 如果此方法调用另一个事务方法怎么办 使用Spring Transactional 使用Spring Transactional 上述代码简化为 Transactionalpublic void businessLogic() {... use entity manager inside a transaction ...} 这更加方便和易读是当前在Spring中推荐的处理事务的推荐方法。 通过使用Transactional 可以自动处理许多重要方面例如事务传播。 在这种情况下如果businessLogic()调用了另一个事务方法则该方法可以选择加入正在进行的事务。 潜在的不利之处在于这种强大的机制隐藏了幕后发生的事情从而在无法正常工作时很难进行调试。 Transactional的关键点之一是要考虑两个单独的概念每个概念都有自己的范围和生命周期 持久性环境 数据库事务 事务注释本身定义了单个数据库事务的范围。 数据库事务在持久性上下文的范围内发生。 持久性上下文在JPA中是EntityManager 使用Hibernate Session在内部实现当使用Hibernate作为持久性提供程序时。 持久性上下文只是一个同步器对象该对象跟踪一组有限的Java对象的状态并确保最终将这些对象上的更改持久化回到数据库中。 这与数据库事务的概念非常不同。 一个实体管理器可用于多个数据库事务 而实际上经常是这样。 EntityManager何时跨多个数据库事务 最常见的情况是当应用程序使用“打开视图中的会话”模式来处理延迟的初始化异常时请参见上一篇博客文章以了解其优缺点 。 在这种情况下在视图层中运行的查询与用于业务逻辑的查询不在单独的数据库事务中但是它们是通过同一实体管理器进行的。 另一种情况是开发人员将持久性上下文标记为PersistenceContextType.EXTENDED 这意味着它可以承受多个请求。 什么定义了EntityManager vs Transaction关系 这实际上是应用程序开发人员的选择但是使用JPA实体管理器的最常见方法是使用“每个应用程序事务的实体管理器”模式。 这是注入实体管理器的最常见方法 PersistenceContextprivate EntityManager em; 在这里默认情况下我们处于“每个事务实体管理器”模式。 在这种模式下如果我们在Transactional方法内使用此实体管理器则该方法将在单个数据库事务中运行。 PersistenceContext如何工作 想到的一个问题是鉴于实体管理器的生命周期如此短并且每个请求通常有多个实体因此PersistenceContext如何在容器启动时仅注入一次实体管理器。 答案是它不能 EntityManager是一个接口注入到bean中的不是实体管理器本身而是上下文感知的代理 它将在运行时委派给具体的实体管理器。 通常用于代理的具体类是SharedEntityManagerInvocationHandler 可以在调试器的帮助下进行确认。 Transactional如何工作 实现EntityManager的持久性上下文代理不是使声明式事务管理工作所需的唯一组件。 实际上需要三个独立的组件 EntityManager代理本身 交易方面 交易经理 让我们逐一检查一下看看它们如何相互作用。 交易方面 事务方面是在注释的业务方法之前和之后都被调用的“周围”方面。 实现方面的具体类是TransactionInterceptor 。 事务方面有两个主要职责 在“之前”时刻该方面提供了一个挂钩点用于确定要调用的业务方法是否应在正在进行的数据库事务范围内运行或者是否应该启动新的单独事务。 在“之后”时刻方面需要确定是应该提交事务回滚事务还是保持运行。 在“之前”时刻事务方面本身不包含任何决策逻辑如果需要则启动新事务的决策将委托给事务管理器。 交易经理 交易经理需要提供以下两个问题的答案 是否应该创建一个新的实体管理器 是否应该启动新的数据库事务 这需要在调用事务方面“之前”逻辑时确定。 交易经理将根据以下内容做出决定 一项交易是否已经进行的事实 事务方法的传播属性例如 REQUIRES_NEW始终启动新事务 如果交易经理决定创建新交易则它将 创建一个新的实体经理 将实体管理器绑定到当前线程 从数据库连接池中获取连接 将连接绑定到当前线程 实体管理器和连接都使用ThreadLocal变量绑定到当前线程。 它们在事务运行时存储在线程中并且当不再需要它们时由事务管理器来清理它们。 程序中需要当前实体管理器或连接的任何部分都可以从线程中检索它们。 正是这样做的一个程序组件是EntityManager代理。 EntityManager代理 最后一步是EntityManager代理我们之前已经介绍过。 以业务方法为例 entityManager.persist() 此调用未直接调用实体管理器。 相反业务方法调用代理该代理从线程事务管理器放置在该线程中中检索当前实体管理器。 现在知道了Transactional机制的哪些移动部分让我们Transactional这项工作所需的常规Spring配置。 全部放在一起 让我们研究一下如何设置使事务注释正确工作所需的三个组件。 我们首先定义实体管理器工厂。 这将允许通过持久性上下文注释注入Entity Manager代理 Configurationpublic class EntityManagerFactoriesConfiguration {Autowiredprivate DataSource dataSource;Bean(name entityManagerFactory)public LocalContainerEntityManagerFactoryBean emf() {LocalContainerEntityManagerFactoryBean emf ...emf.setDataSource(dataSource);emf.setPackagesToScan(new String[] {your.package});emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());return emf;}} 下一步是配置事务管理器并将事务方面应用于Transactional注释的类 ConfigurationEnableTransactionManagementpublic class TransactionManagersConfig {AutowiredEntityManagerFactory emf;Autowiredprivate DataSource dataSource;Bean(name transactionManager)public PlatformTransactionManager transactionManager() {JpaTransactionManager tm new JpaTransactionManager();tm.setEntityManagerFactory(emf);tm.setDataSource(dataSource);return tm;}} 注释EnableTransactionManagement告诉Spring带有Transactional注释的类应使用Transactional Aspect包装。 这样 Transactional现在可以使用了。 结论 Spring声明式事务管理机制非常强大但是很容易被滥用或错误配置。 在机制无法正常工作或无法正常工作的情况下进行故障排除时了解其内部工作方式将很有帮助。 要牢记的最重要的一点是实际上有两个概念需要考虑数据库事务和持久性上下文每个都有其自身不容易显现的生命周期。 将来的帖子将讨论事务注释的最常见陷阱以及如何避免它们。 翻译自: https://www.javacodegeeks.com/2014/06/how-does-spring-transactional-really-work.html