事务控制
事务
简介
当我们的事务涉及到多个表,或者多个sql语句时,需要我们进行加入到一个事务中数据库事务 | 偷掉月亮 (moonshuo.cn)
在哪里添加事务???
我们仔细观察在我们的三层结构dao,service与controller层中,dao控制单个语句的执行,但是service是对象完成的操作的地方,比如添加学生,查询表格最终都是service集成了dao的一个或者多个sql,事务控制应该在service进行
两种控制事务的方式:
- jdbc:connection.commit(),connection.rollback()
- mybaits:sqlSession.commit,sqlSession.rollback
事务的处理方式有什么不足:
- 不同的数据库访问技术,处理事务的对象,方法不同
- 需要掌握数据库事务的处理逻辑,什么时间提交等等
解决方法:
spring提供了处理事务的统一模型 ,可以完成mybaits等等事务处理机制
(来自动力节点)
事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback
事务管理器是一个接口和他的众多实现类。
接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
mybatis访问数据库—spring创建好的是DataSourceTransactionManager
hibernate访问数据库—-spring创建的是HibernateTransactionManager
方法
我们不需要进行代码编写,但是需要告诉spring使用哪一种技术
1.需要声明事务管理器对象
2.开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务。
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知
1 |
|
3.在你的方法的上面加入@Trancational
其他
你的业务方法需要什么样的事务,说明需要事务的类型。
说明方法需要的事务:
1)事务的隔离级别:有4个值。
DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
➢ SERIALIZABLE:串行化。不存在并发问题。
- 事务的超时时间: 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。
单位是秒, 整数值, 默认是 -1.
3)事务的传播行为 : 控制业务方法是不是有事务的, 是什么样的事务的。
7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。
1 | //指定的方法必须在事务内执行,若当前存在事务,就加入到当前事务中,若当前没有事务,则创建一个新的事务,是spring默认的事务传播行为,比如方法1调用方法2,而方法1本身已经声明事务,而方法2被 PROPAGATION_REQUIRED修饰,那么方法2与方法1同属于一个事务,如果方法1不是事务,那么方法2会自动创建一个事务 |
当我们的业务方法执行成功,没有异常抛出,spring在方法执行之后提交事务,调用commit方法,而当出现异常的时候,spring调用回滚方法
示例演示
代码
商品表
销售记录表
1 | public class BuyServiceImpl implements BuyService { |
我们正常测试会没有发生异常,但是加入我们人为的加入异常措施,我们会发现出现了问题
解决
@Transactional
适合中小项目使用的, 注解方案。
spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等
propageation:设置事务的传播属性
isolcation:设置事务的隔离级别
readOnly:设置该方法对数据库的操作是否只读
rollbackFor表示需要回滚的异常类
等等
使用步骤
- 声明事务管理器
1 | <!--启用事务管理器的事务处理--> |
- 方法上面加注解
1 |
|
此时就不会发生以上的错误了
Aspectj
适合大型项目,拥有很多的类方法需要大量的配置,使得业务方法和事务配置完全分离
加入依赖
1 | <dependency> |
声明事务管理器,方法需要的事务属性
1 | <!--启用事务管理器的事务处理--> |
配置aop,指定那些类需要创建代理
1 | <!--配置aop,表示那些类需要应用事务--> |
这样程序的事务也完成了