Spring数据访问,个人认为还是比较易懂的~
1.1. Spring Framework 的事务支持模型的优点
数据访问
1. Transaction Management
全面的事务支持是使用 Spring Framework 的最令人信服的理由之一。Spring Framework 为事务管理提供了一致的抽象,具有以下优点:
-
跨不同事务 API 的一致编程模型,例如 Java 事务 API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA)。
-
支持声明式事务管理。
-
比复杂的事务 API(例如 JTA)更简单的用于程序化事务管理的 API。
-
与 Spring 的数据访问抽象的完美集成。
以下部分描述了 Spring Framework 的事务特性和技术:
-
Spring Framework 事务支持模型的优点描述了为什么要使用 Spring Framework 的事务抽象而不是 EJB 容器管理事务 (CMT) 或选择通过专有 API(例如 Hibernate)驱动本地事务。
-
理解 Spring Framework 事务抽象 概述了核心类并描述了如何
DataSource
从各种来源配置和获取实例。 -
将资源与事务同步描述了应用程序代码如何确保正确创建、重用和清理资源。
-
声明式事务管理描述了对声明式事务管理的支持。
-
程序化事务管理涵盖了对程序化(即显式编码)事务管理的支持。
-
事务绑定事件描述了如何在事务中使用应用程序事件。
1.1. Spring Framework 的事务支持模型的优点
传统上,Java EE 开发人员对事务管理有两种选择:全局事务或本地事务,两者都有很大的局限性。在接下来的两节中回顾全局和本地事务管理,然后讨论 Spring Framework 的事务管理支持如何解决全局和本地事务模型的局限性。
1.1.1. Global Transactions
全局事务可以使用多个事务资源,通常是关系数据库和消息队列。
1.1.2. Local Transactions
本地事务是特定于资源的,例如与 JDBC 连接关联的事务。本地事务可能更易于使用,但有一个明显的缺点:它们不能跨多个事务资源工作。
1.1.3. Spring Framework 的一致编程模型
Spring 解决了全局事务和本地事务的缺点。它允许应用程序开发人员在任何环境中使用一致的编程模型。
通过编程事务管理,开发人员可以使用 Spring Framework 事务抽象,它可以在任何底层事务基础架构上运行。使用首选声明式模型,开发人员通常很少编写或不编写与事务管理相关的代码,因此不依赖于 Spring Framework 事务 API 或任何其他事务 API。
1.2. 理解 Spring 框架事务抽象
Spring 事务抽象的关键是事务策略的概念。事务策略由 定义TransactionManager
,特别是 org.springframework.transaction.PlatformTransactionManager
命令式事务管理的org.springframework.transaction.ReactiveTransactionManager
接口和反应式事务管理的 接口。以下清单显示了PlatformTransactionManager
API的定义 :
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
以下清单显示了由 定义的事务策略 org.springframework.transaction.ReactiveTransactionManager
:
public interface ReactiveTransactionManager extends TransactionManager {
Mono<ReactiveTransaction> getReactiveTransaction(TransactionDefinition definition) throws TransactionException;
Mono<Void> commit(ReactiveTransaction status) throws TransactionException;
Mono<Void> rollback(ReactiveTransaction status) throws TransactionException;
}
反应式事务管理器主要是一个服务提供者接口 (SPI),尽管您可以从应用程序代码中以编程方式使用它。因为ReactiveTransactionManager
是一个接口,所以可以根据需要轻松模拟或存根。
该TransactionDefinition
接口指定:
-
传播:通常,事务范围内的所有代码都在该事务中运行。但是,如果在事务上下文已经存在时运行事务方法,您可以指定行为。例如,代码可以在现有事务中继续运行(常见情况),或者可以暂停现有事务并创建新事务。Spring 提供了 EJB CMT 中熟悉的所有事务传播选项。
-
隔离度:此事务与其他事务的工作隔离的程度。例如,这个事务可以看到来自其他事务的未提交的写入吗?
-
超时:此事务在超时和被底层事务基础设施自动回滚之前运行的时间。
-
只读状态:当您的代码读取但不修改数据时,您可以使用只读事务。在某些情况下,只读事务可能是一种有用的优化,例如当您使用 Hibernate 时。
该TransactionStatus
接口为事务代码提供了一种简单的方式来控制事务执行和查询事务状态。这些概念应该很熟悉,因为它们对所有事务 API 都是通用的。以下清单显示了 TransactionStatus
界面:
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
@Override
boolean isNewTransaction();
boolean hasSavepoint();
@Override
void setRollbackOnly();
@Override
boolean isRollbackOnly();
void flush();
@Override
boolean isCompleted();
}
以下示例展示了如何定义本地PlatformTransactionManager
实现(在本例中,使用普通 JDBC。)
datasource
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
然后相关的PlatformTransactionManager
bean 定义有一个对DataSource
定义的引用 。它应该类似于以下示例:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
如果在 Java EE 容器中使用 JTA,那么将DataSource
通过 JNDI 获得的容器与 Spring 的JtaTransactionManager
. 以下示例显示了 JTA 和 JNDI 查找版本的样子:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee
https://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- other <bean/> definitions here -->
</beans>
1.2.1. 休眠事务设置
还可以轻松地使用 Hibernate 本地事务,
以下示例声明sessionFactory
和txManager
bean:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
如果使用 Hibernate 和 Java EE 容器管理的 JTA 事务,应该使用与JtaTransactionManager
前面的 JTA 示例相同的 JDBC,如以下示例所示。此外,建议通过其事务协调器以及可能的连接释放模式配置使 Hibernate 了解 JTA:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.transaction.coordinator_class=jta
hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
或者,可以传递给JtaTransactionManager
LocalSessionFactoryBean
以强制执行相同的默认值:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.transaction.coordinator_class=jta
hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
1.3. 将资源与事务同步
如何创建不同的事务管理器以及它们如何链接到需要同步到事务的相关资源(例如DataSourceTransactionManager
到 JDBC DataSource
、HibernateTransactionManager
到 HibernateSessionFactory
等)现在应该很清楚了。
1.3.1. 高级同步方法
首选方法是使用 Spring 的最高级别基于模板的持久性集成 API,或者使用带有事务感知工厂 bean 或代理的本机 ORM API 来管理本机资源工厂。
1.3.2. 低级同步方法
诸如DataSourceUtils
(对于JDBC)、EntityManagerFactoryUtils
(对于JPA)、 SessionFactoryUtils
(对于Hibernate)等类存在于较低级别。当您希望应用程序代码直接处理原生持久化 API 的资源类型时,您可以使用这些类来确保获得适当的 Spring Framework 管理的实例,事务(可选)同步,并且过程中发生的异常是正确映射到一致的 API。例如,在JDBC的情况下,您可以使用Spring的类代替 传统的JDBC方式在 上调用getConnection()
方法,如下所示:
DataSource``org.springframework.jdbc.datasource.DataSourceUtils
Connection conn = DataSourceUtils.getConnection(dataSource);
如果现有事务已经有一个与之同步(链接)的连接,则返回该实例。否则,该方法调用会触发新连接的创建,该连接(可选)同步到任何现有事务,并可供后续在同一事务中重用。如前所述, any SQLException
包装在 Spring Framework 中CannotGetJdbcConnectionException
,Spring Framework 的未检查DataAccessException
类型层次结构之一。这种方法提供了比从 中轻松获取的更多信息,SQLException
并确保了跨数据库甚至跨不同持久性技术的可移植性。
这种方法也可以在没有 Spring 事务管理的情况下工作(事务同步是可选的),因此无论是否使用 Spring 进行事务管理,都可以使用它。
当然,一旦使用了 Spring 的 JDBC 支持、JPA 支持或 Hibernate 支持通常不喜使用DataSourceUtils
或其他辅助类,因为通过 Spring 抽象工作比直接使用相关 API 更快乐。例如,如果使用 SpringJdbcTemplate
或 jdbc.object
包来简化您对 JDBC 的使用,则正确的连接检索发生在幕后,无需编写任何特殊代码。
1.3.3. TransactionAwareDataSourceProxy
在最底层存在TransactionAwareDataSourceProxy
类。这是一个 target 的代理DataSource
,它包装了 targetDataSource
以增加对 Spring 管理的事务的感知。在这方面,它类似于DataSource
Java EE 服务器提供的事务性 JNDI 。
几乎不需要或不想使用此类,除非必须调用现有代码并传递标准 JDBCDataSource
接口实现。在这种情况下,此代码可能可用但正在参与 Spring 管理的事务。可以使用前面提到的更高级别的抽象来编写新代码。
1.4. 声明式事务管理
Spring Framework 的声明式事务管理通过 Spring 面向方面的编程 (AOP) 成为可能。但是,由于事务方面代码随 Spring Framework 发行版一起提供并且可以样板方式使用,因此通常不必理解 AOP 概念即可有效使用此代码。
Spring Framework 的声明式事务管理类似于 EJB CMT,因为可以将事务行为(或缺少它&