隔离级别越高, 越能保证数据的完整性和一致性, 但是对并发性能的影响也越大. 对于多数应用程序, 可以优先考虑把数据库系统的隔离级别设为 Read Committed. 它能够避免脏读取, 而且具有较好的并发性能. 尽管它会导致不可重复读, 幻读和第二类丢失更新这些并发问题, 在可能出现这类问题的个别场合, 可以由应用程序采用悲观锁或乐观锁来控制.
数据库的几种隔离级别:
READ UNCOMMITTED(读未提交数据): 允许事务读取未被其他事务提交的变更数据, 会出现脏读, 不可重复读和幻读问题.
READ COMMITTED(读已提交数据): 只允许事务读取已经被其他事务提交的变更数据, 可避免脏读, 仍会出现不可重复读和幻读问题.
REPEATABLE READ(可重复读): 确保事务可以多次从一个字段中读取相同的值, 在此事务持续期间, 禁止其他事务对此字段的更新, 可以避免脏读和不可重复读, 仍会出现幻读问题.
SERIALIZABLE(序列化): 确保事务可以从一个表中读取相同的行, 在这个事务持续期间, 禁止其他事务对该表执行插入, 更新和删除操作, 可避免所有并发问题, 但性能非常低.
Oracle 支持两种事务隔离级别:
READ COMMITTED(默认事务隔离级别),SERIALIZABLE
MySQL 支持四种事务隔离级别, 其中 REPEATABLE READ 为默认事务隔离级别.
通过上面可以知道多事务同时运行, 如果不采用以上四种隔离机制, 可能会产生多个并发问题, 其中包括脏读, 不可重复读和幻读, 下面就解释下这几种并发问题:
存在两个事物 (T1,T2) 同时运行
脏读: T1 读取了已经被 T2 修改但还未提交的字段, 由于某种原因, T2 事物回滚, 则 T1 读取的内容是临时且无效的.
不可重复读: T1 读取一个字段, 之后 T2 更新了该字段, T1 在此读取该字段值发生了变化.
幻读: T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行, 之后 T1 在此读取该表会多出几行.
二, 数据库事务的特性: 原子性, 一致性, 隔离性, 持久性
原子性: 事务的原子性指的是, 事务中包含的程序作为数据库的逻辑工作单位, 它所做的对数据修改操作要么全部执行, 要么完全不执行, 这种特性称为原子性.(简单地说就是, 几个对于数据库的操作要么全执行, 要么全不执行, 即同时成功起作用或同时失败没影响)
一致性: 事务一致性值得是在一个事务执行之前和执行之后数据库都必须处于一致性状态(中途是否一致不用管), 这种特性称为一致性.(如果数据库的状态满足所有的完整性约束, 就说该数据库是一致的. 一致性处理数据库中对所有语义的保护. 如: 客户 K1 要向客户 K2 转账, K1 账户减少的金额就是 K2 账户增加的金额, 在转账之前 K1 和 K2 账户的金额之和与转账之后 K1 和 K2 账户的金额之和是一样的, 在转账期间可能不满足这种一致性, 但事务前后是数据库数据是一致的)
隔离性: 隔离性指的是并发的事务是相互隔离的.(一个事务内部的操作及正在操作的数据必须封装起来, 不被其它企图进行修改的事务看到)
持久性: 持久性指当系统或介质发生故障时, 确保已提交的更新不能丢失.(一个事务提交, DBMS 保证它对数据库中数据的改变应该是永久性的, 可以经受任何系统故障, 持久性通过数据库备份和恢复来保证)
三, 传播行为
PROPAGATION_REQUIRED: 如果当前没有事务, 就创建一个新事务, 如果当前存在事务, 就加入该事务, 该设置是最常用的设置.
PROPAGATION_SUPPORTS: 支持当前事务, 如果当前存在事务, 就加入该事务, 如果当前不存在事务, 就以非事务执行.'
PROPAGATION_MANDATORY: 支持当前事务, 如果当前存在事务, 就加入该事务, 如果当前不存在事务, 就抛出异常.
PROPAGATION_REQUIRES_NEW: 创建新事务, 无论当前存不存在事务, 都创建新事务.
PROPAGATION_NOT_SUPPORTED: 以非事务方式执行操作, 如果当前存在事务, 就把当前事务挂起.
PROPAGATION_NEVER: 以非事务方式执行, 如果当前存在事务, 则抛出异常.
PROPAGATION_NESTED: 如果当前存在事务, 则在嵌套事务内执行. 如果当前没有事务, 则执行与 PROPAGATION_REQUIRED 类似的操作.
1: PROPAGATION_REQUIRED
加入当前正要执行的事务不在另外一个事务里, 那么就起一个新的事务
比如说, ServiceB.methodB 的事务级别定义为 PROPAGATION_REQUIRED, 那么由于执行 ServiceA.methodA 的时候,
ServiceA.methodA 已经起了事务, 这时调用 ServiceB.methodB,ServiceB.methodB 看到自己已经运行在 ServiceA.methodA
的事务内部, 就不再起新的事务. 而假如 ServiceA.methodA 运行的时候发现自己没有在事务中, 他就会为自己分配一个事务.
这样, 在 ServiceA.methodA 或者在 ServiceB.methodB 内的任何地方出现异常, 事务都会被回滚. 即使 ServiceB.methodB 的事务已经被
提交, 但是 ServiceA.methodA 在接下来 fail 要回滚, ServiceB.methodB 也要回滚
2: PROPAGATION_SUPPORTS
如果当前在事务中, 即以事务的形式运行, 如果当前不再一个事务中, 那么就以非事务的形式运行
3: PROPAGATION_MANDATORY
必须在一个事务中运行. 也就是说, 他只能被一个父事务调用. 否则, 他就要抛出异常
4: PROPAGATION_REQUIRES_NEW
这个就比较绕口了. 比如我们设计 ServiceA.methodA 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB 的事务级别为 PROPAGATION_REQUIRES_NEW,
那么当执行到 ServiceB.methodB 的时候, ServiceA.methodA 所在的事务就会挂起, ServiceB.methodB 会起一个新的事务, 等待 ServiceB.methodB 的事务完成以后,
他才继续执行. 他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了. 因为 ServiceB.methodB 是新起一个事务, 那么就是存在
两个不同的事务. 如果 ServiceB.methodB 已经提交, 那么 ServiceA.methodA 失败回滚, ServiceB.methodB 是不会回滚的. 如果 ServiceB.methodB 失败回滚,
如果他抛出的异常被 ServiceA.methodA 捕获, ServiceA.methodA 事务仍然可能提交.
5: PROPAGATION_NOT_SUPPORTED
当前不支持事务. 比如 ServiceA.methodA 的事务级别是 PROPAGATION_REQUIRED , 而 ServiceB.methodB 的事务级别是 PROPAGATION_NOT_SUPPORTED ,
那么当执行到 ServiceB.methodB 时, ServiceA.methodA 的事务挂起, 而他以非事务的状态运行完, 再继续 ServiceA.methodA 的事务.
6: PROPAGATION_NEVER
不能在事务中运行. 假设 ServiceA.methodA 的事务级别是 PROPAGATION_REQUIRED, 而 ServiceB.methodB 的事务级别是 PROPAGATION_NEVER ,
那么 ServiceB.methodB 就要抛出异常了.
7: PROPAGATION_NESTED
理解 Nested 的关键是 savepoint. 他与 PROPAGATION_REQUIRES_NEW 的区别是, PROPAGATION_REQUIRES_NEW 另起一个事务, 将会与他的父事务相互独立,
而 Nested 的事务和他的父事务是相依的, 他的提交是要等和他的父事务一块提交的. 也就是说, 如果父事务最后回滚, 他也要回滚的.
而 Nested 事务的好处是他有一个 savepoint.
来源: http://www.bubuko.com/infodetail-2566574.html