一、概述
(一)基本概念
1 、什么是Spring事务处理?
什么是事务处理我就不想回答了。 Spring 的事务处理,可以说是 Spring AOP 的一种实现。因为事务处理是所谓方面( Aspect )的一个子集。因此默认情况下,事务处理是利用 Java 动态代理机制实现的,这样就必须先定义一个接口,然后再编写实现;而对于没有接口的 Javabean ,则通过 CGLIB 实现。这部分是 Spring AOP 部分的内容。
2 、两种事务处理方式
和 EJB 一样, Spring 也提供两种事务处理方式,一种是编程式事务处理;一种是声明式事务处理。
(二)框架图
|
|
(三)何时使用什么
如果需要大量的事务处理,就用声明式事务处理,如果很少的事务处理,就用编程式
二、详细
编程式事务处理与声明式事务处理
(一)编程式事务处理
1 、使用TransactionTemplate进行事务处理(Spring进行commit和rollback)
( 1 )使用事务处理的类
import javax.sql.DataSource;
import org.springframework.jdbc.core.*;
import org.springframework.transaction.*;
import org.springframework.dao.*;
public class bookDAO{
private DataSource dataSource;// 依赖注入 dataSource ,管理数据库
private PlatformTransationManager transactionManager;// 依赖注入管理事务
public void setDataSource(DataSource dataSource){
this.dataSource=dataSource;
}
public void setTransactionManager(PlatformTransationManager transactionManager){
this. transactionManager= transactionManager;
}
public int create(String msg){
TransactionTemplate transactionTemplate=new TransactionTemplate(transactionManager);
// 调用 transactionTemplate 的 execute 方法进行事务管理
Object result= transactionTemplate.execute (
// 这是一个回调函数,实现了 TransactionCallback 接口的 doInTransaction 方法,就是在这个方法里写数据库新增数据的操作
{
public Object doInTransaction(TransactionStatus status)
{
// 数据库操作代码
return resultObject;
}
}
[U1] )
}
}
如果不想返回结果( resultObject ),则可以用 TransactionCallbackWithoutResult 来实现 TransactionCallback 接口,代码如下:
new TransactionCallback WithoutResult ()
{
public Object doInTransaction WithoutResult (TransactionStatus status)
{
// 数据库操作代码
}
}
( 2 )配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!— 设 定dataSource à
<bean id=”dataSource” class=”org.springframework.jdbc.datasource.DriverManagerDataSource”>
<!— 使用SQL Server 数 据 库 à
<property name=”driverClassName”>
<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
</property>
<property name=”url”>
<value>jdbc:Microsoft:sqlserver://localhost:1433/stdb</value>
</property>
<property name=”name”>
<value>admin</value>
</property>
<property name=”msg”>
<value>admin</value>
</property>
</bean>
<!— 设定 transactionManager à
<bean id=”transactionManager”
class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
<property name=”dataSource”>
<ref bean=”dataSource”/>
</property>
</bean>
<!— 示例中 DAO-->
<bean id=”bookDAO” class=”com.bookDAO”>
<property name=”dataSource”>
<ref bean=”dataSource”/>
</property>
<property name=”transactionManager”>
<ref bean=”transactionManager”>
</property>
</bean>
</beans>
这样 Spring 就可以自动进行 commit 和 rollback 这两个操作了。粉色部分是为了和 bookDAO 中的粉色部分相匹配。
2 、使用JdbcTemplate进行事务处理(硬编码进行commit和rollback)
( 1 )使用事务处理的类
import javax.sql.DataSource;
import org.springframework.jdbc.core.*;
import org.springframework.transaction.*;
import org.springframework.dao.*;
public class bookDAO{
private DataSource dataSource;// 依赖注入 dataSource ,管理数据库
private PlatformTransationManager transactionManager;// 依赖注入管理事务
public void setDataSource(DataSource dataSource){
this.dataSource=dataSource;
}
public void setTransactionManager(PlatformTransationManager transactionManager){
this. transactionManager= transactionManager;
}
public int create(String msg){
/* TransactionTemplate transactionTemplate=new TransactionTemplate(transactionManager);
Object result= transactionTemplate.execute (
new TransactionCallback()
{
public Object doInTransaction(TransactionStatus status)
{
return resultObject;
}
}
)*/
// 使用下面的代码替换上面注释掉的部分
DefaultTransactionDefinition def =new DefaultTransactionDefinition();
TransactionStatus status=transactionManager.getTransaction(def);
try
{
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
jdbcTemplate.update(“INSERT INTO book VALUES(1,’gf’,’Mastering Spring’)”);
}
catch(DataAccessException ex)
{
transactionzManager.rollback(status);
throw ex;
}
finally
{
transactionManager.commit(status);
}
}
}
( 2 )配置文件
同上
( 二)声明式事务处理
( 1 )使用事务处理的类
import javax.sql.DataSource;
import org.springframework.jdbc.core.*;
import org.springframework.transaction.*;
import org.springframework.dao.*;
public class bookDAO{
private DataSource dataSource;// 依赖注入 dataSource ,管理数据库
private PlatformTransationManager transactionManager;// 依赖注入管理事务
public void setDataSource(DataSource dataSource){
this.dataSource=dataSource;
}
public void setTransactionManager(PlatformTransationManager transactionManager){
this. transactionManager= transactionManager;
}
public int create(String msg){
① /* TransactionTemplate transactionTemplate=new TransactionTemplate(transactionManager);
Object result= transactionTemplate.execute (
new TransactionCallback()
{
public Object doInTransaction(TransactionStatus status)
{
return resultObject;
}
}
)*/
② /* DefaultTransactionDefinition def=new DefaultTransactionDefinition();
TransactionStatus status=transactionManager.getTransaction(def);
try
{
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
jdbcTemplate.update(“INSERT INTO book VALUES(1,’gf’,’Mastering Spring’)”);
}
catch(DataAccessException ex)
{
transactionzManager.rollback(status);
throw ex;
}
finally
{
transactionManager.commit(status);
} */
// 使用下面的代码替换上面注释掉的部分
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
jdbcTemplate.update(“INSERT INFO book VALUES(1,’gf’,’Mastering Spring’)”);
/ / 与 ② 相比,此段代码省去了 commit 和 rollback 事务处理语句;与 ① 相比,不必实现 TransactionCallback 接口
}
}
( 2 )配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!— 设 定dataSource à
<bean id=”dataSource” class=”org.springframework.jdbc.datasource.DriverManagerDataSource”>
<!— 使用SQL Server 数 据 库 à
<property name=”driverClassName”>
<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
</property>
<property name=”url”>
<value>jdbc:Microsoft:sqlserver://localhost:1433/stdb</value>
</property>
<property name=”name”>
<value>admin</value>
</property>
<property name=”msg”>
<value>admin</value>
</property>
</bean>
<!— 设定 transactionManager à
<bean id=”transactionManager”
class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
<property name=”dataSource”>
<ref bean=”dataSource”/>
</property>
</bean>
<!— 示例中 DAO-->
<bean id=”bookDAO” class=”com.bookDAO”>
<property name=”dataSource”>
<ref bean=”dataSource”/>
</property>
<!— 与编程式事务处理相比,在 DAO 设置中去掉了这个属性,把它放到了代理类中。 - à
<!— <property name=”transactionManager”>
<ref bean=”transactionManager”>
</property> - à
</bean>
<!— 声明式事务处理 - à
<bean id=”bookDAOProxy” class=”org.springframework.transaction.interceptor.Transation.ProxyFactoryBean”>
<property name=”transacionManager”>
<ref bean=”transacionMaganer”/>
</property>
<property name=”target”>
<ref bean=”bookDAO”/>
</property>
<property name=”transactionAttributes”>
<props>
<!-- 表示对 bookDAO 中的 create 方法进行事务处理,并指明当前没有事务就新建一个(用 PROPAGATION_REQUIRED 常量来表示的) à
<prop key=”create * ”>PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
续:
事务管理是企业级应用程序中必不可少的一项技术,用于确保数据的完整性和一致性。
作为企业级应用程序框架,Spring在不同的事务管理API上定义了一个抽象层。
程序员不必太了解底层的事务管理API,就能使用Spring事务管理机制。
如同EJB中的BMT(Bean-managed transaction,Bean管理事务)和CMT(Container-managed transaction,容器管理事务)方法一样,Spring即支持编程式的事务管理也支持声明式的事务管理。Spring事务支持的目标是给POJO添加事务功能,提供一种EJB事务的可选方法。
编程式事务管理:是将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。如果方法正常完成,通常会提交事务;如果方法抛出某种类型的异常,则回滚事务。
然而在使用编程式事务管理时,必须在每个事务操作中包含另外的事务管理代码。因此要在每个操作中重复样板事务代码。此外还很难对不同的应用程序启用和禁用事务管理。事务管理是横切关注点。
声明式事务管理:在大多数情况下要比编程式事务管理更好用。它将事务管理代码从业务中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring同Spring AOP框架支持声明式事务管理。这样可以帮助你更加轻松的为应用程序启用事务,并定义一致的事务策略。然而,声明式事务管理不太灵活,因为无法通过代码精确的控制事务。
事务属性:
原子性
一致性
隔离性
持久性
1.选择事务管理器实现
问题:一般情况下,如果应用程序只涉及单个数据源,可以只在数据库连接上调用commit()和rollback()方法来管理事务。
然而,如果事务扩展到多个数据源,或者你更喜欢使用JavaEE应用服务器提供的事务管理功能,就可以选择JTA(Java Transaction API,Java事务API)。此外,你可能还需要为不同的对象/关系映射框架(如:Hibernate或JPA)调用不同专用事务API。
因此,必须为不同的技术处理不同的事务API。很难从一组API切换到另一组API。
实现方案:PlateformTransactionManager是所有Spring事务管理器的通用接口。Spring内置了几个实现,用于不同事物管理API。
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img534.ph.126.net/syqMRbbdqX8LRNJtLffEkw==/2650368380708657804.jpg)
如果在应用程序中只需要处理一个数据源,并且通过JDBC进行存取,DataSourceTransactionManager应该满足需求。
如果在JavaEE应用服务器上涌JTA进行事务管理,就应该使用JtaTransactionManager从应该服务器查找事务。
如果使用ORM存取数据库,并且通过JDBC进行存取,就应该选取相应的事务管理器。
事务管理器以普通Bean的形式声明在SpringIoC容器里。例如,下面的Bean配置声明了一个DataSourceTransactionManager实例。
它需要设置dataSource属性,以便可以对这个数据源上的连接进行事务管理。
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img691.ph.126.net/8vAzCKqpRxTvhAbeViRtBg==/54043195529731305.jpg)
2.用事务管理器API编程式地管理事务
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img844.ph.126.net/poGKhxzc5hqspHXxsl1q-Q==/1888978568707148775.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img699.ph.126.net/vS8rRUzdQyP4Wwz46f9BHg==/56013520366724762.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img687.ph.126.net/A8IzHldRoqGLZet3_laH_Q==/2815312717061245794.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img850.ph.126.net/RPgtvUpi1lZ-mXbK0ewL5w==/575053377420868526.jpg)
3.用事务模板编程式地管理事务
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img617.ph.126.net/UAffNgmPFSC6B50IwsgxXg==/1907837392146532301.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img161.ph.126.net/bG6t9LlKYmMOI01S4VTPlg==/1441996305690261862.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img115.ph.126.net/c5uE46AsLWCVWNPk7wo2Dg==/2004664784135040245.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img846.ph.126.net/V_ubraxOYxM47tux4Yd9pg==/753789987633203730.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img847.ph.126.net/XcfQ0rhpdYDzSu4qHPSYiA==/765330461678209632.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img472.ph.126.net/xkpY0n1NvGaRg2hj3yXlxg==/3083558369865860406.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img848.ph.126.net/J-nYzNiU9ZYBGwM52jFeMA==/2091359076962304154.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img1.ph.126.net/2C0uCitkRJVN24J_Qgv7uQ==/3186859686320047585.jpg)
4.用经典的Spring AOP声明式地管理事务
问题:事务管理是一种横切关注点,AOP是实现它的理想方法。然而,如果要在Spring1.x中声明式地管理事务,就必须使用经典Spring AOP方法。
解决方案:Spring为事务管理提供了一个环绕通知,称作TransactionInterceptor。这个通知像事务模板一样控制这事务管理流程,但它使用于整个方法体,而不是任意的代码块。默认情况下,在方法开始之前,这个通知就启动了一个新的事务。如果方法抛出未受检的异常,上午就被回滚。否则完成方法之后就提交事务。
在经典Spring AOP中,必须利用ProxyFactoryBean为Bean创建一个代理来应用TransactionInterceptor通知。由于事务管理在企业应用中非常普遍,因此Spring提供了一个TransactionProxyFactoryBean类,它专用于创建事务代理。
Dao类:
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img852.ph.126.net/KznNb8Pk45AmIXFMQr8oLQ==/2730588749071333746.jpg)
Spring IoC容器:
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img850.ph.126.net/25zLixHmCcYDi5AL4sZayw==/2709759600794887143.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img104.ph.126.net/dClKz1vYoW1qo0BCQsb3Dw==/2035908506550187591.jpg)
Main类:
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img382.ph.126.net/hMH2lNQz6xY543nKA4FcGA==/2450239672267448919.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img685.ph.126.net/cv5iEpF1S23wP2j0XDtutw==/2800113068318880971.jpg)
5.用事务通知声明式的管理事务
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img170.ph.126.net/tdLroAJwnhT0O4TPt7Mgaw==/1599903767624848437.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img858.ph.126.net/7oWRSDDsBtckdJnLHPszBA==/672162244386432151.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img96.ph.126.net/_qQ4Ck6zdgFRd9RJiE_M2A==/2048856355478843239.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img458.ph.126.net/fvCl6XOSajqEUrryAroNQQ==/2551570663882802303.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img1.ph.126.net/90Gti3-onrHnH0RtZXzOUw==/3194740985668205646.jpg)
Main类:
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img842.ph.126.net/JWGmoV48iSHTkq2zCAy6ng==/877357502409071661.jpg)
6.用@Transactional注解声明式地管理事务
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img542.ph.126.net/cYBUfGoK7O_L8g_mOEA4mQ==/1328843365052201785.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img534.ph.126.net/Zj9H9yANG9lsWSeQGgbF_w==/103019841477292408.jpg)
Spring IoC容器:
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img685.ph.126.net/M0z0unlZ4ASKQgqvh0O6Rw==/1098033884149508152.jpg)
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img853.ph.126.net/xPc_rg8DdvUUK6tY7qjgLg==/611645124393289447.jpg)
7.设置传播事务属性
问题描述:当事务方法别另一个方法调用时,必须制定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能启动一个新事务,并在它自己的事务中运行。
解决方法:事务的传播行为可以由传播事务属性制定。Spring定义了7种传播行为,这些行为时在org.springframework.transaction.TransactionDefinition中定义的。并非所有事务管理器类型都支持这些传播行为。
![Spring中的事务管理 - lrf8933 - 罗若峰](http://img849.ph.126.net/ykITL4e8jnXKuRDA68zoyA==/2699063551679861624.jpg)