1. 事务基本概念mysql
事务是指在数据库系统执行过程当中的一个逻辑单元,由有限的数据库操做序列构成。spring
1.1 事务的基本特色sql
事务具备四个属性:ACID本别是: 原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)。数据库
原子性(要么成功要么失败):一个事务是不可分割的基本单位,事务中的全部操做要么要么所有都作,要么所有不作。并发
一致性(数据库状态变化):事务必须使数据库从一个状态变化到另外一个状态。一致性与原子性密切相关。oracle
隔离性(互不影响):一个事务的执行不能被其余事务干扰。不一样的事务之间互补干扰。性能
持久性(不能撤销):一个事务一旦提交,它对数据库中数据的改变就是永久性的。atom
2. 事务的基本原理url
spring事务的本质是对数据库事务的支持,没有数据库事务的支持,spring是没法提供事务功能的。spa
对jdbc操做数据库要使用事务,使用以下步骤:
(1) 获取链接 Connection con = DriverManager.getConnection(url,username,password);
(2) 开启事务 con.setAutoCommit(false);
(3) 执行数据库curd操做
(4) 提交事务/回滚事务 con.commit()/con.rollback();
(5) 关闭链接 conn.close();
在是用spring的事务管理功能后,咱们能够不用再写2和4的代码,而是由spring自动完成, 具体如何自动完成的,使用到了aop和动态代理的相关技术。
3. spring事务的传播特性
spring事务的传播特性就是定义同时存在多个事务的时候,spring应该如何处理这些事务的行为。
这些属性定义在TransactionDefinition中,具体常量解释以下:
常量名称 | 常量解释 |
PROPAGATION_REQUIRED | 支持当前事务,若是当前没有事务就新建一个事务。这是最多见的选择,也是spring默认的事务的传播 |
PROPAGATION_REQUIRES_NEW | 新建事务,若是当前存在事务,就把当前事务挂起。新建的事务和被挂起的事务是两个独立的事务,外层事务失败回滚以后不能回滚内部事务执行的结果, 内存事务失败抛出异常,外层事务捕获,也能够不处理回滚操做。 |
PROPAGATION_SUPPORTS | 支持当前事务,若是当前没有事务,就以非事务的方式运行 |
PROPAGATION_NOT_SUPPORTED | 以非事务的方式运行,若是当前存在事务,就把当前事务挂起 |
PROPAGATION_MANDATORY | 支持当前事务,若是当前没有事务,就抛出异常 |
PROPAGATION_NEVER | 以非事务的方式运行,若是当前存在事务,就抛出异常 |
PROPAGATION_NESTED | 若是一个活动的事务存在,则运行在嵌套的事务中,若是没有活动的事务,则按PROPAGATION_REQUIRED执行。使用一个单独的事务,这个事务拥有多个能够回滚的事务保存点。 |
4. 数据库事务隔离级别
脏读: 在一个事务中读取到另外一个事务未提交的数据。
不可重复度:在一个事务中两次的查询结果不同(针对update操做)。
幻读:在一个事务中两次的查询结果不同(正对insert操做)
√ 可能出现 × 不会出现 | |||
隔离级别 | 脏读 | 不可重复读 | 幻读 |
ISOLATION_READ_UNCOMMITED | √ | √ | √ |
ISOLATION_READ_COMMITED | × | √ | √ |
ISOLATION_REPEATABLE_READ | × | × | √ |
ISOLATION_SERIALIZABLE | × | × | × |
ISOLATION_READ_UNCOMMITED:事务最低的隔离级别,它容许另一个事务看到当前事务未提交的数据。可能产生藏独、不可重复度、幻读。
ISOLATION_READ_COMMITED:另外一个事务不能读取当前事务未提交的数据。
ISOLATION_REPEATABLE_READ:防止了脏读、不可重复读出现,可是可能出现幻读。
ISOLATION_SERIALIZABLE:防止了脏读、不可重复读、幻读,可靠性最好的事务级别,可是执行效率也是最慢的,慎用。
数据库隔离级别越高,越能保证数据的完整性和一致性,可是对并发性能的影响也越大。多数数据的默认隔离级别都是read commited,如sqlServer,oracle;少数数据库隔离级别默认是repeatable read,如mysqlInnoDB。
5. spring中的事务隔离级别
ISOLATION_DEFAULT | spring默认的隔离级别,使用数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITED | 同数据库事务隔离级别 |
ISLATION_READ_COMMITED | 同数据库事务隔离级别 |
ISOLATION_REPEATABLE_READ | 同数据库事务隔离级别 |
ISOLATION_SERIALIZEABLE | 同数据库事务隔离级别 |
6. 举例说明事务的嵌套,理解spring事务传播机制
假设外层事务serviceA的methodA()方法调用内层的serviceB的methodB()方法
PROPAGATION_REQUIRED
若是serviceB.methodB()的事务定义为PROPAGATION_REQUIRED,若是servieA.methodA()执行的时候已经开启了事务,那么serviceB.methodB()在执行的时候发现已经在methodA的事务中,那么就不会再新建一个事务;若是methodA()没有在事务中,那么methodB()在执行的时候就会新建一个事务。这样在methodA()和methodB()中的任何地方出现异常,事务都会回滚,即便被methodA中catch住,也会由于是一个事物在methodB的时候标记为事物失败而抛出一个UnexpectedRollbackException(org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only)致使回滚。
PROPAGATION_REQUIRES_NEW
执行到method()的时候,methodA()所在的事务就会挂起,methodB()会新开启一个事务,methodB()所在的事务执行完之后method所在的事务才会继续执行。它与PROPAGATION_REQUIRED的区别在于回滚的程度。由于B是新起的一个事务,若是B已经提交,A失败回滚,那么B也是不会回滚; 若是B失败回滚,抛出的异常被A捕获(try catch住),若是在catch中没有抛出异常,那么A不会回滚;若是catch中抛出异常而且是A上rollbackFor设置的异常,则回滚,若是不是,则不会回滚。
serviceA#methodA() -> serviceB#methodB()
若是methodB() 抛出异常,在methodA()中try catch住,若是没有从新抛出或者抛出的异常不是methodA方法rollbackFor设置的异常,那么 methodA 不会滚,methodB回滚;
若是methodB()抛出异常,在methodA()中try catch住,而且从新抛出了methodA上rollbackFor设置的异常,那么methodA回滚,methodB回滚;
若是methodB()抛出异常,在methodA()中没有try catch住,那么methodA methodB都会回滚;
若是只有methodA抛出异常,那么methodA回滚,methodB不会滚
PROPAGATION_NESTED
serviceA#methodA() -> serviceB#methodB()
若是methodB()抛出异常,若是在methodA中catch处理,那么methodA不会滚,methodB回滚;若是methodA没有catch处理,那么methodA,methodB都回滚
若是methodA()抛出异常,那么methodA,methodB都回滚。
7. 对于同一个类中事物方法调用失效的状况处理
首先须要设置exposeProxy=true, 经过xml方式或者注解方式:<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true" /> 或者 @EnableAspectJAutoProxy(exposeProxy=true)
调用:((UserService)AopContext.currentProxy()).testExpose1();