一、事务的四大特性
1、原子性:多个修改操作,一起成功执行,或者一起执行失败;
2、一致性:对不同事物操作前后,保证事物的状态一致性,即我增加的数量等于你减少的数量
3、隔离性:是说事务之间操作时彼此不受影响的,即多个角色对同一事物操作,减少彼此受到的影响,
事务的隔离级别分为:
读未提交,read-uncommite,会因此脏读,幻读和不可重复度
读已提交,read-commite,避免了脏读
重复度,repeatable-read,避免了脏读和幻读
串行化,serializable,最严格的隔离级别,再次模式下所有的事务按照顺序依次执行,避免以上所有情况。
4、持久性:数据在数据库保存。
二、spring事务管理有许多细节需要注意,对整个事务框架接口的整体了解有助于我们理解事务,下面通过了解spring的事务接口来理解spring管理实务的策略
1、其实spring是开放PlatformTranctionManger接口给操作数据库的框架的事务来实现的,他并不直接管理事务,而是提供各种各样对应的事务管理器;具体看下图:
![]()
2、PlatformTranctionManger接口提供了三个抽象方法,获取tranctionStatus对象的、事务提交操作和事务回滚方法。从这里可以看出spring并不关系事务的及具体实现方式,只是给你们提供相同的事务处理模型。
下面分贝说一下,各个持久层框架具体的事务实现方式
一、先从各持久框架的持久成实现类说起
1、sprinJdbc:使用springJdbc进行持久化,事务管理需要使用DataSourceTranctionManger,接下使用xml方式把它装配到应用程序的上下文中:如下
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
实际上DataSourceTranctionManger是通过调用java.sql.Connection对象来管理事务的,其中Connection通过datasource获去,然后通过connection的commit和rollback方法进行提交或者回滚。
其实其他持久成框架实现策略都基本相同,不信接着往下看。
2、Hibernate:使用Hibernate进行持久化操作,事务需要使用HibernateTranctionManger,具体引入到程序上下文环境的xml配置为:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
其中HiberanateTranctionManger是通过调用org.hiberanate.Tranction来管理的,然后Tranction是通过HibernateSession获得,最后调用Tranction的commit和rollBack方法来实现。
似曾相识的感觉,
3、springJpa相似,使用JpaTransactionManager来管理事务,下面说下xml引入方式:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
接着JpaTranctionManger需要装配一个Jpa实体管理工厂(javax.persistence.EntityMangerFactory接口的任一实现),然后JpaTranctionManger需要使用工厂产生的JPA EntityManger来构建事务。
4、如果应用程序没有使用以上所述的事务管理,或者是跨越了多个事务管理源(比如两个或者是多个不同的数据源),
此时需要使用 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() 方法回滚。
三、下面说一下说一下项目中具体的事务配置,一般存在两种方式,配置xml和注解
前言:
Spring 事务配置
1. 添加事务和AOP的命名空间
2. 开启AOP代理
3. 配置事务管理器
4. 配置事务通知
5. 配置AOP
1、springJdbc
事务的注解配置:
<!-- 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 异常捕获原理:
被拦截的方法需显式抛出异常,并不能经任何处理,这样aop 代理才能捕获到方法的异常,才能进行回滚,默认情况
下 aop 只捕获 runtimeexception 的异常,但可以通过配置来捕获特定的异常并回滚换句话说在 service 的方法中
不使用 try catch 或者在 catch 中最后加上 throw new RunTimeexcetpion(),这样程序异常时才能被 aop 捕获
进而回滚。
事务的xml配置:
I、
在spring.xml中配置事务的命名空间
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
配置如下:
<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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
II、设置AOP代理
<!-- 开启AOP代理 -->
<aop:aspectj-autoproxy />
III、配置事务管理器
<!-- 事务管理器定义 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
III、配置事务相关通知
一般来说增删改方法 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 将触发事务回滚
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--对以add update delete query开头的所有方法进行事务处理-->
<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)
支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
IIII、配置AOP:
<!-- aop 切面定义 (切入点和通知) -->
<aop:config>
<!-- 设置切入点 设置需要被拦截的方法 -->
<aop:pointcut expression="execution(* com.xxxx.service..*.*(..) )" id="cut" />
<!-- 设置通知 事务通知 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
<aop:advisor