在一个业务流程当中,通常需要多条DML(insert delete update) 语句共同联合才能完成,这多条DML语句必须同时乐成,或者同时失败,如许才能包管数据的安全。事务的四个处理过程:
多条DML要么同时乐成,要么同时失败,这叫做事务。事务(Transaction)
事务的四个特性:
- 第一步:开启事务(start transaction)
- 第二步:执行核心业务代码
- 第三步:提交事务(假如核心业务处理过程中没有出现异常)(commit transaction)
- 第四步:回滚事务(假如核心业务处理过程中出现异常)(rollback transaction)
3. 引入事务场景
- 原子性:事务是最小的工作单元,不可再分
- 同等性:事务要求要么同时乐成,要么同时失败,事务前和事务后的总量不变
- 隔离性:事务和事务之间因为有隔离性,才可以包管互不干扰
- 长期性:长期性是事务结束的标志。
转账:首先我们需要查询对应账户上是否有该满足的余额;假如够,我们就需要更新数据(修改数据);所以定义两个方法就行:根据账户查询,根据账户修改
定义一个举行转账操作的业务
PlatformTransactionManager接口:spring 事务管理器的核心接口,在Spring6中它有两个实现:假如要在Spring6中使用 JdbcTemplate,就要使用 DataSourceTransactionManager 来管理事务。(Spring 内置写好了,可以直接用)
- DataSourceTransactionManager:支持JdbcTemplate、MyBatis、Hibernate等事务管理。
- JtaTransactionManager:支持分布式事务管理。
配置事务管理器,需要根据对应数据源里面的账户暗码等信息,管理连接数据库,从而开启事务(开启事务,提交事务,回滚事务)等操作
- 在类上添加该@Transactional 注解,则表示该类中所有的方法都有事务了(都举行了事务上的控制,回滚了)
- 在某个方法上添加@Transactional注解,则表示只有这个方法使用了事务(举行了事务上的控制,回滚)其他的方法,并没有举行事务上的控制。
一般参加了事务的同时,也需要交给Spring IOC 容器举行管理 。
虽然出现异常了,再次查看数据库表中数据:通过测试,发现数据没有变化,事务起作用了。
这里我们测试,在 AccountServicelmpl 类当中的 save() 方法创建一个新的账户“"act-003", 1000.0”,然后在 AccountServicelmpl 类的 save() 方法当中,调用 AccountServicelmpl2类当中的 save( ) 方法,添加 "act-004", 1000.0 新的账户信息。
我们这里添加两个新的账户,一个是“act-003" 是 在AccountServicelmpl 类当中的 save() 方法 保存的,而另一个则是“act-004”账户是在,AccountServicelmpl2 类当中的 save() 方法保存的,同时在这个AccountServicelmpl2 类当中的 save() 方法,添加上异常,导致添加账户失败,按照
我们的REQUIRED:支持当前事务,假如不存在就新建一个(默认)《没有事务就新建,有就参加事务,简单的说就是共用同一个事务处理》 的特点,该两个添加账户的操作,归属于同一个事务,此中一个添加账户信息失败了,就全部失败。事务发生回滚操作。
下面我们将 AccountServicelmpl2 类当中的 save() 方法 上的事务流传行为设置为:REQUIRES_NEW 举行测试,再次测试添加两个账户信息的操作。同样开启对 AccountServicelmpl 2 类当中的 save() 方法,添加上异常。
在 AccountServicelmp1 当中的 save() 添加4.4.3 事务的隔离级别上的设置
act-003 账户乐成了,并没有受到 AccountServicelmp2
当中的save()的异常的出现的影响,导致添加失败,
因为这两个不同的类当中的 save()方法上,使用的
并不是同一个事务管理的,而是使用的各自不同的事务
管理的,所以AccountServicelmp2 类当中的 save() 发生了异常,导致了 AccountServiceImp2 类
当中的 save() 方法当中的事务,举行了一个事务的回滚,自然就添加失败了。
事务的隔离级别包括四个级别:
- 脏读:读取到没有提交的数据库的数据,叫做脏读
- 不可重复读:在同一个事务当中,第一次和第二次读取的数据不一样。(并发,多线程就会涉及的不可重复读)
- 幻读:读到的数据是假的
隔离级别脏读不可重复读幻读读未提交有有有读提交无有有可重复读无无有序列化无无无在Spring框架中隔离级别在spring中以枚举范例存在:
- 读未提交:READ_UNCOMMITTED
- 这种隔离级别,存在脏读题目,所谓的脏读(dirty read)表示可以或许读取到其它事务未提交的数据。
- 读提交:READ_COMMITTED
- 办理了脏读题目,其它事务提交之后才能读到,但存在不可重复读题目(Oracel 默认)
- 可重复读:REPEATABLE_READ
- 办理了不可重复度,可以达到可重复读结果,只要当前事务不结束,读取到的数据一直都是一样的。但存在幻读 题目。MySQL默认 是个隔离级别
- 序列化:SERIALIZABLE
- 办理了幻读题目,事务排序执行。但不支持并发。
怎么测试:一个service负责插入,一个service负责查询。负责插入的service要模拟延迟。
IsolationService2 类 save()方法负责,插入一个账户信息 ”act-005“,同时睡眠12秒中,当其还在睡眠当中时(没有提交给数据库,而是在内存当中)的时候,我们的IsolationService1 getByActno( ) 方法根据其插入的“act-005” 账户去查,这时候的 act-005 还在内存当中,我们并没有提交给数据库,看看能否查到?
留意这里有个坑,事务的超时时间指的是哪段时间?如下测试:
在当前事务当中,最后一条DML语句执行之前的时间。假如最后一条DML语句反面很多很多业务逻辑,这些业务代码执行的时间是不被计入超时时间。
我们首先将 DML 语句放在 睡眠 12 秒之前,看看反面的业务处理时间,是否会被记录到超时时间内,会(则超时了,事务会发生回滚);不会(则没有超时,不计入反面的时间,事务不发生回滚)
留意:对于数据源以及JdbcTemplate, DataSourceTransactionManager 事务上的管理,我们可以使用 @Bean 举行注解式开发:首先在配置类上,写明如下注解
Spring 框架,看到这个 @Bean 注解后,会调用这个被标注的方法,这个方法的返回值是一个Java对象,这个Java对象会自动纳入 IOC容器管理,返回的对象就是Spring 容器当中的一个Bean 了。并且这个 Bean 的名字是:dataSource
同 getDataSource 方法()
8. 最后:
- 运行Spring 举行事务处理
- 基于注解方式
- 基于XML配置方式
- 事务上的理解
- 事务属性上的配置:
- 事务的流传行为
- 事务的隔离级别
- 事务的超时设置:超时设置是以最后一个 DML 语句的时间举行计时的(不包括最后一条DML语句反面的,不是 DML语句的业务上处理的运行的时间)
- 只读事务上的设置,提高查询效率
- 设置定义哪些异常回滚事务,不回滚事务
- 事务全注解式开发
- 声明事务之xml 实现方式
- 留意:在Spirng 当中,使用applicationContext.getBean(当中的,xxx.class) 要于返回值范例同等,不然会报范例不同等上的错误。如下:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上罗致了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |