这篇文章主要介绍“java事务的详细讲解”,在日常操作中,相信很多人在java事务的详细讲解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java事务的详细讲解”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
成都创新互联专注为客户提供全方位的互联网综合服务,包含不限于网站制作、网站设计、康县网络推广、成都小程序开发、康县网络营销、康县企业策划、康县品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;成都创新互联为所有大学生创业者提供康县建站搭建服务,24小时服务热线:028-86922220,官方网址:www.cdcxhl.com
我们要理解下事务概念: 什么是事务呢?事务是并发控制的单位,是用户定义的一个操作序列。有四个特性(ACID):
原子性(Atomicity): 事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。
一致性(Consistency): 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(Isolation): 一个事务的执行不能被其他事务干扰。
持续性/永久性(Durability): 一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
以上是书面解释,简单来说就是把你的操作统一化,要么所有操作都成功,要么就都不成功,如果执行中有某一项操作失败,其之前所有的操作都回滚到未执行这一系列操作之前的状态。
先理解这三种由于并发访问导致的数据读取问题,再理解事务隔离级别就简单多了。
A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。就好像原本的数据比较干净、纯粹,此时由于B事务更改了它,这个数据变得不再纯粹。这个时候A事务立即读取了这个脏数据,但事务B良心发现,又用回滚把数据恢复成原来干净、纯粹的样子,而事务A却什么都不知道,最终结果就是事务A读取了此次的脏数据,称为脏读。
这种情况常发生于转账与取款操作中
事务A在执行读取操作,由整个事务A比较大,前后读取同一条数据需要经历很长的时间 。而在事务A第一次读取数据,比如此时读取了小明的年龄为20岁,事务B执行更改操作,将小明的年龄更改为30岁,此时事务A第二次读取到小明的年龄时,发现其年龄是30岁,和之前的数据不一样了,也就是数据不重复了,系统不可以读取到重复的数据,成为不可重复读。
事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。
小总结:不可重复读和幻读到底有什么区别?
(1) 不可重复读是读取了其他事务更改的数据,针对update操作
解决:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。
(2) 幻读是读取了其他事务新增的数据,针对insert和delete操作
解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。
这时候再理解事务隔离级别就简单多了呢。
SQL 标准定义的四种隔离级别被 ANSI(美国国家标准学会)和 ISO/IEC(国际标准)采用,每种级别对事务的处理能力会有不同程度的影响。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。
数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed 、Repeatable read 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题。
默认值,表示使用底层数据库的默认隔离级别。大部分数据库为READ_COMMITTED(MySQL默认REPEATABLE_READ)
该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 在该隔离级别下事务都是串行顺序执行的,MySQL 数据库的 InnoDB 引擎会给读操作隐式加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。
mysql中,默认的事务隔离级别是可重复读(repeatable-read),为了解决不可重复读,innodb采用了MVCC(多版本并发控制)来解决这一问题。 MVCC是利用在每条数据后面加了隐藏的两列(创建版本号和删除版本号),每个事务在开始的时候都会有一个递增的版本号,用来和查询到的每行记录的版本号进行比较。 MYSQL MVCC
先来介绍下Spring事务传播行为的使用方法:
@Transactional(propagation=Propagation.REQUIRED) public void test() { //todo something }
注解@Transactional 通过使用 propagation 属性设置,例如:@Transactional(propagation = Propagation.REQUIRED)
它的propagation属性取值有以下几种:
public enum Propagation { REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED), SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS), MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY), REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW), NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED), NEVER(TransactionDefinition.PROPAGATION_NEVER), NESTED(TransactionDefinition.PROPAGATION_NESTED); }
事务传播行为:
REQUIRED
:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
SUPPORTS
:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
MANDATORY
:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
REQUIRES_NEW
:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
NOT_SUPPORTED
:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
NEVER
:以非事务方式运行,如果当前存在事务,则抛出异常。
NESTED
:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED
Spring 支持“编程式事务
”管理和“声明式事务
”管理两种方式:
1编程式事务
: 编程式事务使用 TransactionTemplate 或者直接使用底层的 PlatformTransactionManager
实现事务。 对于编程式事务 Spring 比较推荐使用 TransactionTemplate 来对事务进行管理。
2声明式事务
: 声明式事务是建立在 AOP 之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况“提交”或者“回滚”事务。
编程式事务允许用户在代码中精确定义事务的边界。
声明式事务有助于用户将操作与事务规则进行解耦,它是基于 AOP 交由 Spring 容器实现,是开发人员只重点关注业务逻辑实现。
编程式事务侵入到了业务代码里面,但是提供了更加纤细的事务管理。而声明式事务基于 AOP,所以既能起到事务作用,又可以不影响业务代码的具体实现。一般而言比较推荐使用声明式事务,尤其是使用 @Transactional 注解,它能很好地帮助开发者实现事务的同时,也减少代码开发量,且使代码看起来更加清爽整洁。
一般来说编程式事务有两种方法可以实现: 模板事务的方式(TransactionTemplate)
和 平台事务管理器方式(PlatformTransactionManager)
模板事务的方式(TransactionTemplate): 主要是使用 TransactionTemplate 类实现事务,这也是 Spring 官方比较推荐的一种编程式使用方式;
例:
① 获取模板对象 TransactionTemplate;
② 选择事务结果类型;
③ 业务数据操作处理;
④ 业务执行完成事务提交或者发生异常进行回滚;
其中 TransactionTemplate 的 execute 能接受两种类型参数执行事务,分别为:
TransactionCallback