本篇博文主要包含:
- 事务的特性
-原子性
-一致性
-隔离性
-持久性 - 事务的实现方式
-编程式事务
-声明式事务(原理:AOP+环绕通知+异常通知) - 事务的七种传播行为
-REQUIRED(默认):支持当前事务,如果当前没有事务,就新建一个事务
-REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起
-SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行
-NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
-MANDATORY:支持当前事务,如果当前没有事务,就抛出异常
-NEVER:以非事务方式执行,如果当前存在事务,则抛出异常
-NESTED:如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务,其行为类似于REQUIRED
事物:保证数据的一致性
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
- 编程式事务控制
自己手动控制事务,细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制。(比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚)
1.1 配置事物
<bean id="DataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
1.2 事务工具类TransactionUtile
@Component
public class TransactionUtile {
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
//开启事务
public TransactionStatus begin() {
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
return transaction;
}
//提交事务
public void commit(TransactionStatus transaction) {
dataSourceTransactionManager.commit(transaction);
}
//回滚事务
public void rollback(TransactionStatus transaction) {
dataSourceTransactionManager.rollback(transaction);
}
}
1.3 调用事务
public void insertStuInfo1() {
//开启事务
TransactionStatus begin = transactionUtile.begin();
try {
StuInfo stuInfo = new StuInfo();
stuInfo.setStuName("yy");
stuInfo.setStuGender(1);
stuInfoService.insertStuInfo(stuInfo);
int i= 1/0;
//关闭事务
transactionUtile.commit(begin);
} catch (Exception e) {
e.printStackTrace();
//回滚事务
transactionUtile.rollback(begin);
}
}
报异常时,会事务回滚。注意使用事务时要调用commit或rollback方法将事务关闭。
2. 声明式事务控制
Spring提供了对事务的管理, 这个就叫声明式事务管理。
Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。
Spring声明式事务管理,核心实现就是基于Aop。
粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。(因为aop拦截的是方法。)
声明式事务原理解析:AOP+环绕通知+异常通知,业务层(即使用事务的地方)一定要将异常抛给上一层进行处理,不然异常通知不会被调用,导致事务回滚失败。
2.1 声明式事务原理代码演示
1)引入AOP架包依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_2</version>
</dependency>
2)applicationContext.xml配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="reflectUser" class="wmq.fly.reflection.ReflectUser">
<property name="name" value="二和"></property>
<property name="addr" value="下榕树"></property>
</bean>
<!-- 配置事物 -->
<bean id="DataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启AOP -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3)AOP实现声明式事务
//指定一个类为切面类
@Aspect
//注入Spring IOC容器
@Configuration
public class TransactionAop {
@Autowired
private TransactionUtile transactionUtile;
TransactionStatus begin = null;
//定义切入点
@Pointcut("execution(* wmq.fly.mybatis.controller..*(..))")
public void performance() {
}
//异常通知: 出现异常时候执行
@AfterThrowing("performance()")
public void afterThrowing() {
System.out.println("异常通知");
transactionUtile.rollback(begin);
}
//环绕通知: 环绕目标方法执行
@Around("performance()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("我是环绕通知-前");
TransactionStatus begin = transactionUtile.begin();
// HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String methodName = pjp.getSignature().getName();
System.out.println("aop===方法名:"+methodName);
pjp.proceed();
String className = pjp.getTarget().getClass().getName();
System.out.println("aop===类名:"+className);
System.out.println("我是环绕通知-后");
transactionUtile.commit(begin);
}
}
4)测试代码
public void insertStuInfo1() {
StuInfo stuInfo = new StuInfo();
stuInfo.setStuName("y1y");
stuInfo.setStuGender(1);
stuInfoService.insertStuInfo(stuInfo);
//int i= 1/0;
}
2.1 XML方式实现
1)applicationContext.xml配置
<!-- 配置事物 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事物增强-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<!--除了get和find开头的方法都使用事务-->
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="*" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 -->
<aop:config>
<aop:pointcut expression="execution(* wmq.fly.mybatis.controller..*(..))" id="pt" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
</aop:config>
2.2 注解方式实现
1)applicationContext.xml配置
<!-- 配置事物 -->
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解事物 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
2)在方法或类上添加@Transactional
注解
3. 七种传播行为
@Transactional(propagation=Propagation.REQUIRED)
public void propagation01(){
propagation02();
}
@Transactional(propagation=Propagation.REQUIRED)
public void propagation02(){
//TODO
}
1)REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是事务注释的默认设置也是最常见的选择。即如果propagation01()方法存在事务, propagation02()就用propagation01()的,没有就新建。
2)REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。即如果propagation01()方法存在事务,就将propagation01()的挂起, propagation02()就用propagation02()方法的新建。
3)SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。即如果propagation01()方法存在事务, propagation02()就用propagation01()的,没有就以非实物方式执行。
4)NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
5)MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
6)NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7)NESTED:如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务,其行为类似于REQUIRED 。