一、事务与数据库的隔离级别
1、事务的ACID属性
A(Atomicity):原子性,事务要么都成功,要么都失败,是一个整体
C(Consistency):一致性,事务前后数据保持一致,如张三去银行取钱,取了500,则张三到手500,银行扣除500,总数不变
I(Isolation):隔离性,多事务之间互相隔离,不受影响
D(Durability):持久性,事务一旦成功,其改变是永久性的。
2、mysql的隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
未提交读 | 是 | 是 | 是 |
提交读 | 否 | 是 | 是 |
可重复读(默认级别) | 否 | 否 | 是 |
串行化 | 否 | 否 | 否 |
脏读:读到了无用的数据,事务A增加了一条数据未提交,事务B读到了这条数据,最后事务A事务回滚,事务B则读到了脏数据
不可重复读:同一事务两次读,读到的数据不一致,另一事务对数据进行了修改
幻读:同一事务两次读,后一次读到的数据多了,另一事务插入了一条数据。
3、Oracle的隔离级别
支持两种隔离级别:读已提交(默认隔离级别)、串行化
二、spring的事务
1、spring事务的本质是数据库对事务的支持
2、单纯的jdbc想要想要用到事务,可以用以下步骤:
//1、获取连接
Connection con =DrivenManager.getConnection();
//2开启事务
con.setAutoConmmit(false);
//3执行CRUD
//4提交事务/回滚事务
con.commit()/con.rollback();
//5关闭连接
con.close();
而使用用spring @Trancational事务注解,spring会自动实现步骤2、4,那spring是如何字段实现2、4的呢?答案是:在spring启动时,spring通过配置文件或者注解生成相应的springbean,这个时候会查看拥有相关注解的类和方法,并且为这些类及方法生成相应的代理,并根据@Trancational中的参数,进行相关配置的注入,这样就通过代理的手段帮们实现了2、4步骤
真正的数据库底层的事务提交及回滚是通过binlog、redolog实现的
3、spring的隔离级别,与mysql的一致,多了一个默认级别
//默认隔离级别,取数据库的默认隔离级别
Isolation.DEFAULT
//读未提交
Isolation.READ_UNCOMMITTED
//读已提交
Isolation.READ_COMMITTED
//可重复读
Isolation.REPEATABLE_READ
//串行化(能解决脏读、不可重复读、幻读问题,但是效率低)
Isolation.SERIALIZABLE
4、spring的传播机制
支持当前事务 | PROPAGATION_REQUIRED | 如果当前没有事务,则新建,如果有,则加入 |
支持当前事务 | PROPAGATION_SUPPORTS | 支持当前事务,没有事务则不用事务 |
支持当前事务 | PROPAGATION_MANDATORY | 使用当前事务,没有则抛异常 |
不支持当前事务 | PROPAGATION_REQUIRES_NEW | 新建事务,若当前存在事务,则挂起当前事务 |
不支持当前事务 | PROPAGATION_NOT_SUPPORTED | 非事务,挂起当前事务 |
不支持当前事务 | PROPAGATION_NEVER | 非事务,当前存在事务则抛异常 |
内嵌事务 | PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
5、事务对runtimeException(比如空指针、1/0 异常)会回滚,而Exception异常(如文件读写、网络问题)无法回滚,若需要Exception异常也回滚的话需要添加rollback=Exception.class