04 Spring 声明式事务
2022-11-23 01:29:00 1 举报
04 Spring 声明式事务
作者其他创作
大纲/内容
什么是事务?
把一组业务当成一个业务来做;
要么都成功,要么都失败,保证业务操作完整性的一种数据库机制。
Spring JdbcTemplate
什么是JdbcTemplate?
更加方便的操作JDBC
为不同类型的JDBC操作提供了模板方法
它是线程安全的,但建议呢最好还是一个dao对应一个jdbcTemplate
配置及应用
1、添加依赖
pom依赖如下1:
pom依赖如下2:
从下图可以看出,orm已依赖了jdbc和tx(事务)的jar,无需再另外引入
2、配置扫描包
xml配置:
3、JdbcTemplate 配置数据源
a.新建db配置文件
b.JdbcTemplate注入数据源
4、测试获取数据源bean和jdbcTemplate的bean
代码示例:
5、查询单个值:
代码示例:
6、查询实体:
代码示例:
7、查询List实体:
代码示例:
8、新增:
代码示例:
9、修改:
代码示例:
10、删除:
代码示例:
11、具名参数处理:
1、spring配置中新注入NamedParameterJdbcTemplate
2、使用实例:
事务的四大特性
ACID
A 原子性:
原子性指的是 在一组业务操作下 要么都成功 要么都失败
换句话说:在一组增删改查的业务下 要么都提交 要么都回滚
C 一致性:
事务前后的数据要保证数据的一致性
换句话说:在一组的查询业务下 必须要保证前后关联数据的一致性
I 隔离性:
在并发情况下 事物之间要相互隔离
D 持久性:
数据一旦保存就是持久性的
在事务控制方面的分类
编程式事务
在代码中直接加入处理事务的逻辑,可能需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法
代码示例:
声明式事务
在方法的外部添加注解或者直接在配置文件中定义
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理
Spring的AOP恰好可以完成此功能:
事务管理代码的固定模式作为一种横切关注点
通过AOP方法模块化,进而实现声明式事务
声明式事务的配置
1、先配置一个事务管理器,并将数据注入
xml配置:
2、基于注解方式的事务,开启事务的注解驱动
如果基于注解的和xml的事务都配置了会以注解的优先
3、声明事务,进行测试
使用@Transactional注解应该写在哪:
1、可以标记在类上面,则当前类所有的方法都运用上了事务
2、标记在方法,则只是当前方法运用事务
3、也可以类和方法上面同时都存在,
a. 如果类和方法都存在@Transactional会以方法的为准
b. 如果方法上面没有@Transactional会以类上面的为准
建议:
@Transactional写在方法上面,控制粒度更细
@Transactional写在业务逻辑层上,因为只有业务逻辑层才会有嵌套调用的情况
代码示例:
事务配置的属性
1、设置隔离级别
解决并发事务所产生的问题:
并发概念:同一个时间,多个线程同时进行请求,但并不是所有并发情况都会产生问题
什么情况下产生并发问题:在并发情况下,对同一个数据(变量、对象)进行读写操作才会产生并发问题
并发会产生什么问题?
脏读
指:一个事务,读取了另一个事务中没有提交的数据,会在本事务中产生的数据不一致的问题
举例:张三发工资了1000,张三和老婆都取钱了,老婆早0、0001微弱的优势取200元,这个时候张三发现剩800,但是呢这个时候老婆操作出问题了,账户里边还是1000元
解决:
设置张三只读已提交结果1000元
使用@Transactional(isolation = Isolation.READ_COMMITTED)
读已提交:READ COMMITTED
要求Transaction01只能读取Transaction02已提交的修改
不可重复读
指:一个事务中,多次读取相同的数据, 但是读取的结果不一样, 会在本事务中产生数据不一致的问题。
举例:张三发工资了1000,张三和老婆都取钱了,张三早0、0001微弱的优势读1000元,这个时候张三老婆取了200元剩800,操作成功了,这个时候张三想再确认下又读了一下,发现账户上只有800了,从张三这个层面呢,前后读取的数据前后不一致问题,但第二次读取到的数据又不是脏数据,这里问题是在一次请求里张三读到了两个数据不一致的问题
解决:
设置张三在读数据时,设置行锁,这个时候他老婆就不能操作取钱
使用@Transactional(isolation = Isolation.REPEATABLE_READ)
确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。(行锁)
幻影读
指:一个事务中,多次对数据进行整表数据读取(统计),但是结果不一样, 会在本事务中产生数据不一致的问题
举例:张三公司给多少员工统计发了多少钱,人事部门和财务部门同时操作,人事部门以0.001秒的微弱优势统计到3000元,这个时候呢财务部门工资还没发完呢,这个时候财务部门给赵六也发了1000元,这个时候人事部门再统计一次变成了4000元,就出现了一个事务中前后查询结果不一致问题(此现象与不可重复读相似)
解决:
当人事统计查询时,禁止财务进行工资发放
使用@Transactional(isolation = Isolation.SERIALIZABLE)
确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。(表锁)
不可重复读和幻影读的区别:
两者问题相似
不可重复读:只需要锁行,且重点在于update和delete操作
幻读:需要锁表,且重点在于insert操作
隔离级别的比较:
比较如图:
从并发安全考虑:SERIALIZABLE>REPEATABLE_READ>READ_COMMITTED
从运行效率考虑:READ_COMMITTED>REPEATABLE_READ>SERIALIZABLE
默认的事务隔离级别(不同数据库不同默认)
MySQL:
默认:REPEATABLE-READ(可重复读)
查询事务级别:
ORACLE:
默认:READ_COMMITTED(读已提交)
ORACLE:不支持设置可重复读级别
查询事务级别:
针对查询操作:
如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;
如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场
景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持(如:设置不可重复度、幻影读级别)。
景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持(如:设置不可重复度、幻影读级别)。
2、事务的传播特性
指:一个事务方法调用另一个事务方法的时候,即:事务嵌套的时候
spring的事务传播行为:
REQUIRED(默认):
调用它的方法不存在事务时: 它开启新的事务
调用它的方法存在事务:融合到外部事务中
适用增删改查
SUPPORTS:
调用它的方法不存在事务时:不开启新的事务,如:query方法
调用它的方法存在事务:融合到外部事务中
适用查询
REQUIRES_NEW:
调用它的方法不存在事务时:开启新的事务
调用它的方法存在事务:挂起外部事务,创建新的事务
适用于内部事务和外部事务不存在业务关联的情况,如日志在外部事务操作异常后不影响日志的数据记录
建议:在这个场景下时,不建议内外事务方法在同一个类中
NOT_SUPPORTED
调用它的方法不存在事务时:不开启新的事务
调用它的方法存在事务:挂起外部事务
不常用
NEVER
调用它的方法不存在事务时:不开启新的事务
调用它的方法存在事务:抛出异常
不常用
MANDATORY
调用它的方法不存在事务时:抛出异常
调用它的方法存在事务:融合到外部事务中
不常用
3、超时属性(timeout)
timeout:指定事务等待的最长时间(秒)
当前事务访问数据时,有可能访问的数据被别的数据进行加锁的处理,那么此时事务就必须等待,如果等待时间过长给用户造成的体验感差
代码示例:
4、设置事务只读(readOnly)
readonly:只会设置在查询的业务方法中
同:connection.setReadOnly(true) 通知数据库,当前数据库操作是只读,数据库就会对当前只读做相应优化
当将事务设置只读 就必须要你的业务方法里面没有增删改。
代码示例:
5、异常属性(noRollbackFor/rollbackFor)
noRollbackFor:设置哪些异常不回滚
rollbackFor:设置哪些异常回滚
使用示例:
基于xml的事务配置
声明事务切入的所有方法
代码示例:
明确切点匹配到的方法哪些方法需要使用事务
代码示例:
注解方式和XML方式的比较
注解方式:控制力度更细
XML方式:一次配置一劳永逸的方式,同时还增强项目业务方法的约定
0 条评论
下一页