博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring事务隔离级别,事务传播行为
阅读量:6452 次
发布时间:2019-06-23

本文共 4673 字,大约阅读时间需要 15 分钟。

什么是事务: 
事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败.

Spring事务的隔离性(5种)

在讲隔离界别前,我们先来讲讲下基础知识

事务的特性(ACID)

原子性 (atomicity):强调事务的不可分割.

一致性 (consistency):事务的执行的前后数据的完整性保持一致.
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
持久性(durability) :事务一旦结束,数据就持久到数据库

 

可能发生的数据安全问题

脏读:另一个事务还未提交,就已经读到数据未提交的数据。

不可重复读:在同一个事务中,读取一次数据,当另一个数据修改数据提交事务后,再次读取数据与上一次读取数据不同。

幻读:在同一个事务中,读取一次数据的数量。当另一个事务增加/删除一些数据时,数据数量与第一次不同。

 

MySQL默认隔离级别,可重复读

1.读未提交(最低事务隔离界别):可能发生问题 脏读,不可重复读,幻读

2.读已提交  解决问题:脏读  可能发生问题 不可重复读,幻读

3.可重复读(默认隔离级别) 解决问题:脏读 , 不可重复读  可能发生问题幻读

4.串行化 (最高事务隔离级别) 解决问题:脏读,不可重复读,幻读   

 

不难想象隔离级别越高,发生的问题就越少。当然也就意味着同步数据消耗的资源更多。

相信MySQL能把可重复读指定为默认隔离级别,说明其性能已经非常棒了

 

Spring隔离级别

1.ISOLATION_DEFAULT   使用数据库默认隔离级别

2.ISOLATION_READ_UNCOMMITTED 读未提交

3.ISOLATION_READ_COMMITTED 读已提交

4.ISOLATION_REPEATABLE_READ 可重复读

5.ISOLATION_SERIALIZABLE 串行化

 

Spring事务的传播行为(7种)

事务传播:当一个方法中调用另外一个方法时,处理这两个方法间的事务行为(是基于Spring的AOP实现的)

举例:

1 @Transactional(isolation = Isolation.SERIALIZABLE)2 public void method1() {3         method2();4     }5 6 @Transactional(isolation = Isolation.READ_COMMITTED)7 public void method2() {8 }

现在两个方法事务的隔离级别显然不同,那我们对于这种情况就要使用Spring事务传播行为来解决。

 

propagation(传播)

在当前事务中运行:

  1. Propagation.REQUIRED (默认级别)(method1事务存在,使用method1事务。method1事务不存在,新建事务)
  2. PROPAGATION_SUPPORTS(method1事务存在,使用method1事务。method1事务不存在,以非事务方式执行)

  3. PROPAGATION_MANDATORY(强制性)method1事务存在,使用method1事务。method1事务不存在,抛出异常)

不再当前事务中运行:

  1. PROPAGATION_REQUIRES_NEW(method1事务不存在,新建事务。method1事务存在,挂起当前事务,重建一个事务
  2. PROPAGATION_NOT_SUPPORTED(method1事务不存在,新建事务。method1事务存在,挂起当前事务
  3. PROPAGATION_NEVER(method1事务不存在,新建事务。method1事务存在,抛出异常
  1. PROPAGATION_NESTED(嵌套的事务执行)

 

事务的实现 

接下来我们看看都可以怎么实现Spring的事务

1.编程式事务管理

  手动编写事务代码(很少使用)

2.声明式事务管理

  基于TransactionProxyFactoryBean方式(很少使用)

  基于Aspect的XML方式(常用)

  基于注解方式(常用)

 

 

实验代码

dao层方法

1 @Repository("MyDao")2 public interface MyDao {3     int inCount(@Param("name") String name, @Param("count") double count);//增加钱4 5     int outCount(@Param("name") String name, @Param("count") double count);//减少钱6 7     double getCount(@Param("name") String name);//查询钱8 }

查询余额

1 public interface GetCountService {2     double getCount(String name);3 }
1 //获取当前余额 2 @Service 3 public class GetCountServiceImpl implements GetCountService { 4  5     @Autowired 6     private MyDao myDao; 7  8     public double getCount(String name) { 9         return myDao.getCount(name);10     }11 }

转出钱

1 public interface OutService {2     boolean out(String out, double count);3 }
1 @Service2 public class OutServiceImpl implements OutService {3     @Autowired4     private MyDao myDao;5 6     public boolean out(String out, double count) {7         return myDao.outCount(out,count)>0;8     }9 }

转入钱

1 public interface InService {2     boolean in(String in, double count);3 }
1 @Service2 public class InServiceImpl implements InService {3     @Autowired4     private MyDao myDao;5 6     public boolean in(String in, double count) {7         return myDao.inCount(in, count) > 0;8     }9 }

转账

1 public interface MyService {2     boolean transferCount(String out, String in, double count);3 }
1 //实现转账 2 @Service 3 @Transactional 4 //(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT) 5 public class MyServiceImpl implements MyService { 6  7     @Resource 8     private GetCountService getCountService; 9 10     @Resource11     private OutService outService;12 13     @Resource14     private InService inService;15 16 17     // 解耦是为了更多的复用18     // 对于代码模块的修改,不影响接口的使用19     public boolean transferCount(String out, String in, double count) {20         //判断传出金额与当前金额21         if (getCountService.getCount(out) < count) return false;22         //转出钱23         if (!outService.out(out, count)) return false;24 25         //制造异常26         //int i = 10 / 0;27 28         //转入钱29         return inService.in(in, count);30     }31 }

当关上注释的时候,能实现正常的转账功能。

但是手动制造异常除数等于0后发现,传出人的钱少了,但是转入人的钱缺没有发生变化,没有保证数据的原子性。

 

基于Aspect的XML方式

1  
2
3
4
5
6
7
8
9
10
11
12
13
14
15

 

基于注解方式(常用)

首先在XML中配置事务管理器

1   
2
3
4   
5 6
7

开启注解

@Transactional//这些都是spring事务的默认属性,timeout是直接指定的时间@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT,readOnly = false,timeout = 1000,rollbackFor = Exception.class) //这两种实现效果相同

 

对比

第一种明显是一种AOP编程思想(面向切面)

当对所有的切面指定好规则后,所有的方法都不需要在进行配置。

优点:

代码量较少

通过制定规则(insert开头的方法,delete开头的方法,select开头的方法,update开头的方法),不易出错

 

第二种注解的方式

优点

较第一种方法更为灵活。但是在某些情况下冗余太多,导致修改维护的困难

 

结论,没有最好的技术,只有最符合业务的技术,小伙根据自己的情况选择合适的方式实现spring的事务吧。

 

转载于:https://www.cnblogs.com/Gang-Bryant/p/10887216.html

你可能感兴趣的文章
mongodb conf 文件
查看>>
写笔记还是得找官方的博客会更好点
查看>>
计蒜客题库(Python):5、矩阵翻转
查看>>
java keytool 使用总结
查看>>
LNMP tp5 pathinfo路径问题
查看>>
JAR 文件签名 和 JNLP 文件中的 JAR 资源签名证书不一致
查看>>
Android开发SQLite的使用
查看>>
我的友情链接
查看>>
apache源码编译时报错ssl_engine_init.c:546: error: 'STACK' undeclared (first use in this function)...
查看>>
我的友情链接
查看>>
PowerShell PSReadLine特性
查看>>
Linux
查看>>
《Head first HTML与CSS 第二版》读书笔记 第十一章 布局和定位
查看>>
php-fpm 操作
查看>>
linux系统字符编码详解
查看>>
idea 使用lombok
查看>>
Android 本地文件选择
查看>>
321android浏览器
查看>>
SnapView Clone常见问题解答
查看>>
共享器 TS ERROR WINDOWS-FAILED 错误解决方法
查看>>