Spring事务概念
事务的四大特性(ACID)
原子性(Atomicity)
共⽣死,要么全部成功,要么全部失败!
⼀致性(Consistency)
事务在执⾏前后,数据库中数据要保持⼀致性状态。(如转账的过程 账户操作后数据必须保持⼀致)
隔离性(Isolation)
事务与事务之间的执⾏应当是相互隔离互不影响的。(多个⻆色对统⼀记录进行操作必须保证没有任何干扰),当然没有影响是不可能的,为了让影响级别降到最低,通过隔离级别加以限制:
-
READ_UNCOMMITTED (读未提交)
隔离级别最低的⼀种事务级别。在这种隔离级别下,会引发脏读、不可重复读和幻读。
-
READ_COMMITTED (读已提交)
读到的都是别⼈提交后的值。这种隔离级别下,会引发不可重复读和幻读,但避免了脏读。
-
REPEATABLE_READ (可重复读)
这种隔离级别下,会引发幻读,但避免了脏读、不可重复读。
-
SERIALIZABLE (串行化)
最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行。脏读、不可重复读、幻读都不会出现。
持久性(Durability)
事务提交完毕后,数据库中的数据的改变是永久的。
Spring 事务核心接口
Spring 事务管理的实现有许多细节,如果对整个接口框架有个⼤体了解会⾮常有利于我们理解事务,下⾯通过讲解 Spring 的事务接⼝来了解 Spring 实现事务的具体策略。
Spring 并不直接管理事务,⽽是提供了多种事务管理器,他们将事务管理的职责委托给 Hibernate或者 JTA 等持久化机制所提供的相关平台框架的事务来实现。
Spring 事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring 为各个平台如 JDBC、Hibernate 等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。此接⼝的内容如下:
public interface PlatformTransactionManager(){
// 由 TransactionDefinition 得到 TransactionStatus 对象
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交
void commit(TransactionStatus status) throws TransactionException;
// 回滚
void rollback(TransactionStatus status) throws TransactionException; }
从这⾥可知具体的具体的事务管理机制对 Spring 来说是透明的,它并不关心那些,那些是对应各个平台需要关心的,所以 Spring 事务管理的⼀个优点就是为不同的事务 API 提供⼀致的编程模型,如 JTA、JDBC、Hibernate、JPA。下⾯分别介绍各个平台框架实现事务管理的机制。
JDBC 事务
如果应⽤程序中直接使⽤ JDBC 来进⾏持久化,此时使用DataSourceTransactionManager 来处理事务边界。为了使用DataSourceTransactionManager,需要使⽤如下的 XML 将其装配到应⽤程序的上下文定义中:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bea
实际上,DataSourceTransactionManager 是通过调用 java.sql.Connection 来管理事务,而后者是通过 DataSource 获取到的。通过调⽤连接的 commit() ⽅法来提交事务,同样,事务失败则通过调用rollback() ⽅法进行回滚。
Hibernate 事务
如果应⽤程序的持久化是通过 Hibernate 实现的,那么你需要使用HibernateTransactionManager。对于 Hibernate3,需要在 Spring 上下文定义中添加如下的声明:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
sessionFactory 属性需要装配⼀个 Hibernate 的 session ⼯⼚,HibernateTransactionManager 的实现细节是它将事务管理的职责委托给 org.hibernate.Transaction 对象,⽽后者是从 Hibernate Session 中获取到的。当事务成功完成时,HibernateTransactionManager 将会调用Transaction 对象的 commit() ⽅法,反之,将会调⽤ rollback() ⽅法。
Java 持久化 API 事务(JPA)
Hibernate 多年来⼀直是 Java 持久化标准,但是现在 Java 持久化 API 作为真正的 Java 持久化标准进入大家的视野。如果你计划使⽤ JPA 的话,那你需要使⽤ Spring 的 JpaTransactionManager 来处理事务。你需要在 Spring 中这样配置 JpaTransactionManager:
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
JpaTransactionManager 只需要装配⼀个 JPA 实体管理⼯⼚(javax.persistence.EntityManagerFactory 接⼝的任意实现)。 JpaTransactionManager 将与由⼯⼚所产⽣的 JPA EntityManager 合作来构建事务。
Java 原⽣ API 事务
如果应⽤程序没有使⽤以上所述的事务管理,或者是跨越了多个事务管理源(比如两个或者是多个不同的数据源),此时需要使⽤ JtaTransactionManager:
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:/TransactionManager" />
</bean>
JtaTransactionManager 将事务管理的责任委托给 javax.transaction.UserTransaction 和javax.transaction.TransactionManager 对象,其中事务成功完成通过 UserTransaction.commit() ⽅法提交,事务失败通过 UserTransaction.rollback() ⽅法回滚。
Spring事务控制配置
通过 jdbc 持久化事务,对于事务配置实现由两种⽅式即:Xml 配置,注解配置。
XML 配置
添加命名空间
在spring.xml配置⽂件的添加事务和aop的命名空间
事务
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
AOP
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
配置如下
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
设置aop代理
<!-- 开启AOP代理 -->
<aop:aspectj-autoproxy />
配置事务管理器
<!-- 事务管理器定义 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
配置事务相关通知
⼀般来说增删改⽅法 propagation=Required,对于查询⽅法使⽤ read-only=“true”
<!-- 配置事务通知 transaction-manager属性表示这个事务通知是哪个事务管理器管理的-->
<!--
tx:method的属性:
name
是必须的,表示与事务属性关联的⽅法名(业务⽅法名),对切⼊点进⾏细化。
通配符(*)可以⽤来指定⼀批关联到相同的事务属性的⽅法。
如:'get*'、'handle*'、'on*Event'等等.
propagation
不是必须的,默认值是REQUIRED
表示事务传播⾏为, 包括:
REQUIRED,SUPPORTS,MANDATORY,NEVER
REQUIRES_NEW,NOT_SUPPORTED,NESTED
isolation
不是必须的,默认值DEFAULT
表示事务隔离级别(数据库的隔离级别)
timeout
不是必须的,默认值-1(永不超时)
表示事务超时的时间(以秒为单位)
read-only
不是必须的,默认值false不是只读的
表示事务是否只读
rollback-for
不是必须的
表示将被触发进⾏回滚的 Exception(s);以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
no-rollback-for
不是必须的
表示不被触发进⾏回滚的 Exception(s);以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
任何 RuntimeException 将触发事务回滚
-->
<!--对以add update delete query开头的所有⽅法进⾏事务处理-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!--定义什么⽅法需要使⽤事务 name代表的是⽅法名(或⽅法匹配)-->
<!-- 匹配以 add 开头的所有⽅法均加⼊事务 -->
<tx:method name="add*" propagation="REQUIRED" />
<!-- 匹配以 update 开头的所有⽅法均加⼊事务 -->
<tx:method name="update*" propagation="REQUIRED" />
<!-- 匹配以 delete 开头的所有⽅法均加⼊事务 -->
<tx:method name="delete*" propagation="REQUIRED" />
<!-- 匹配以 query 开头的所有⽅法均加⼊事务 -->
<tx:method name="query*" read-only="true" />
</tx:attributes>
</tx:advice>
事务传播⾏为介绍:
@Transactional(propagation=Propagation.REQUIRED)
如果有事务, 那么加⼊事务, 没有的话新建⼀个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个⽅法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建⼀个新的事务,原来的挂起,新的执⾏完毕,继续执⾏⽼的事务
@Transactional(propagation=Propagation.MANDATORY)
必须在⼀个已有的事务中执⾏,否则抛出异常
@Transactional(propagation=Propagation.NEVER)
必须在⼀个没有的事务中执⾏,否则抛出异常(与 Propagation.MANDATORY 相反)
@Transactional(propagation=Propagation.SUPPORTS)
如果其他 bean 调⽤这个⽅法,在其他 bean 中声明事务,那就⽤事务.
如果其他 bean 没有声明事务,那就不⽤事务.
@Transactional(propagation=Propagation.NESTED)
支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
配置aop
<!-- aop 切⾯定义 (切⼊点和通知) -->
<aop:config>
<!-- 设置切⼊点 设置需要被拦截的⽅法 -->
<aop:pointcut expression="execution(* com.xxxx.service..*.*(..) )" id="cut"/>
<!-- 设置通知 事务通知 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
<aop:adviso
注解配置
配置事务管理器
<!-- spring 注解式事务声明 -->
<!-- 事务管理器定义 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
配置注解支持
<tx:annotation-driven transaction-manager="txManager"/>
方法上加入事务注解
Service ⽅法上在需要添加事务的⽅法上加⼊事务注解
@Override
@Transactional(propagation=Propagation.REQUIRED)
public void saveUser(String userName,String userPwd){
User user1=new User();
user1.setUserName(userName);
user1.setUserPwd(userPwd);
userDao.saveUser(user1);
userDao.delUserById(2);
}
备注:默认 spring 事务只在发⽣未被捕获的 runtimeexcetpion 时才回滚。
spring aop 异常捕获原理:
IRED)
public void saveUser(String userName,String userPwd){
User user1=new User();
user1.setUserName(userName);
user1.setUserPwd(userPwd);
userDao.saveUser(user1);
userDao.delUserById(2);
}
备注:默认 **spring** 事务只在发⽣未被捕获的 **runtimeexcetpion** 时才回滚。
**spring aop** 异常捕获原理:
被拦截的⽅法需显式抛出异常,并不能经任何处理,这样**aop** 代理才能捕获到⽅法的异常,才能进⾏回滚,默认情况下 **aop** 只捕获 **runtimeexception** 的异常,但可以通过配置来捕获特定的异常并回滚换句话说在 **service** 的⽅法中不使⽤ **try catch** 或者在 **catch** 中最后加上 **throw new RunTimeexcetpion()**,这样程序异常时才能被 **aop 捕获进⽽回滚**.