Spring事务明明开启了,为什么没起作用???
一、事务的特性(ACID)
1、原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
2、一致性(Consistency):执行事务前后,数据保持一致;
3、隔离性(Isolation):并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;
4、持久性(Durability):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
二、事务的属性
1、隔离级别
2、传播行为
3、回滚规则:这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)。 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
4、是否只读:事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。
5、事务超时:所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
三、并发事务带来的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致一下的问题。
脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入或者删除了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
四、事务隔离级别
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
五、事务传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
不支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
其他情况:
TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
Spring事务常见陷进
一、假如有个接口,它包含两个方法a和b,然后有一个类实现了该接口。在该实现类里在a上标上事务注解、b上不标。
如果b方法中调用了a方法,并且客户端调用了b方法,此时会开启事务吗?
不会,虽然会生成代理类,但是代理类只会对带有注解的方法进行事务增强,而没有注解的方法只会调用目标类的方法(目标类的方法之前,之后都不做处理),然后目标类的b方法再调用自己的a方法。因此目标对象的代码是我们自己写的,和事务没有半毛钱关系,此时你再调用带注解的方法,照样没有事务,只是一个简单的方法调用而已。
四、对于没有实现接口的类,只能使用CGLIB来生成代理。假设有这样一个类,它里面包含public方法,protected方法,private方法,package方法,final方法,static方法,我都给它们加上事务注解,哪些方法会有事务呢?
Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
private修饰的方法,类私有方法,不能被实现和被外部访问,因此不起作用;
final修饰的方法不能被重写,因此也不起作用;
static方法和继承不相干,因此也不起作用;
protected修饰方法可以被重写以添加事务代码;
default修饰方法,如果生成的子类位于同一个包里,就可以被重写;
public方法事务肯定起作用;
注意:代理类需要和目标类实现相同的接口,才能保持和目标类的类型兼容,以及对外接口相同。
只要是以代理方式实现的声明式事务,无论是JDK动态代理,还是CGLIB直接写字节码生成代理,都只有public方法上的事务注解才起作用。而且必须在代理类外部调用才行,如果直接在目标类(例如上个问题中的b方法中调用a方法)里面调用,事务照样不起作用。
Spring事务明明开启了,为什么没起作用???的更多相关文章
- spring事务的开启方式(编程式和声明式)
1.编程式事务:编码方式实现事务管理(代码演示为JDBC事务管理) Spring实现编程式事务,依赖于2大类,分别是上篇文章提到的PlatformTransactionManager,与模版类Tran ...
- 关于Spring 事务管理传播属性的配置及作用-嵌套事务
先了解事务的7种传播属性: PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. PROPAGATION_SUPPORTS -- 支持当前 ...
- Spring事务的开启方式
1.通过注解方式@Transactional @Transactional(rollbackForClassName = { "Exception", "RuntimeE ...
- spring事务传播机制实例讲解
http://kingj.iteye.com/blog/1680350 spring事务传播机制实例讲解 博客分类: spring java历险 天温习spring的事务处理机制,总结 ...
- 2015第24周二Spring事务2
今天继续深入学习SPring事务,发现网上很多文章都是很相似的转载没多少价值,就觉得更有必要把这个主题深入下去,先是摘录那些对自己有用的观点,后期再结合源码进行全面的整理. Spring提供了许多内置 ...
- Spring事务服务
Spring事务服务 (2013-07-22 11:13:36) 转载▼ 标签: 事务管理 ssh 分类: Sping Spring为事务管理提供了一流的支持.同时支持编程式事务和声明式事务.无论是编 ...
- spring事务管理——编程式事务、声明式事务
本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 ...
- 关于Spring事务的原理,以及在事务内开启线程,连接池耗尽问题.
主要以结果为导向解释Spring 事务原理,连接池的消耗,以及事务内开启事务线程要注意的问题. Spring 事务原理这里不多说,网上一搜一大堆,也就是基于AOP配合ThreadLocal实现. 这里 ...
- spring 事务-support 有事务得开启就参加 没有就不参加
spring 事务-support 有事务得开启就参加 没有就不参加
随机推荐
- 攻防世界 reverse tt3441810
tt3441810 tinyctf-2014 附件给了一堆数据,将十六进制数据部分提取出来, flag应该隐藏在里面,(这算啥子re,) 保留可显示字符,然后去除填充字符(找规律 0.0) 处理脚本: ...
- python登陆界面尝试
示例1: """ 编写一个程序 用户可以输入用户名和密码 用户有三次机会 登录成功可以进行相应的操作 输入Q退出系统 """ name_li ...
- day-05-字典
字典的初识 why: 列表可以存储大量的数据,但数据之间的关联性不强 列表的查询速度比较慢.数量越大查询越慢 what:容器型数据类型:dict how: 数据类型的分类(可变与不可变) 可变(不可哈 ...
- python基础(十一):集合的使用(下)
add() 含义:向集合中添加指定的元素: # 注:重复元素没办法加入. >>> s = {1,2,3} >>> s.add(2) >>> s{1 ...
- 【pytest系列】- assert断言的使用
unittest断言方式是用过框架自己实现的,即self.assertEqual()等,当我们使用pytest框架后,这种断言方式是不可用的,因为测试类不会再继承unittest.TestCase类, ...
- H5 端 rem 适配方案与 viewport 适配
H5 端 rem 适配方案与 viewport 适配 rem rem 是 CSS3 新增的一个相对单位(root em,根 em) 只根据当前页面 HTML 页面的 font-size 设置,如果根目 ...
- CLUSTAL W论文解读
CLUSTAL W: improving the sensitivity of progressive multiple sequence alignment through sequence wei ...
- Leedcode算法专题训练(排序)
排序 快速排序 用于求解 Kth Element 问题,也就是第 K 个元素的问题. 可以使用快速排序的 partition() 进行实现.需要先打乱数组,否则最坏情况下时间复杂度为 O(N2). 堆 ...
- 日志收集之filebeat使用介绍
此系列文章一共分为三部分,分为filebeat部分,logstash部分,es部分.这里会按照每天几百亿条的数据量来考虑,去设计.部署.优化这个日志系统,来最大限度的利用资源,并达到一个最优的性能.本 ...
- 测开新手:从0到1,自动化测试接入Jenkins学习
大家好,我叫董鑫,一个在测试开发道路上的新手,之前一直从事手工功能测试,前段时间抽空又温习了一遍老师全栈测开训练营中自动化测试.CICD的知识,最近公司正好有一个项目可以实践练手,趁热打铁,将自动化测 ...