1.数据库事物的四大特性
(1)
原子性:事物包含的操作要么全部成功,要么全部失败
(2)
一致性:事物执行前后,数据库必须保持
一致性状态,
是对数据可见性的约束
(3)
隔离性:多个并发事物之间相互隔离,不会互相干扰
(4)
持久性:事务一旦提交,对数据库的修改就是永久性的
注意:
原子性与一致性的区别:
原子性关注状态,要么全部成功,要么全部失败,不存在部分成功的状态。
一致性关注数据的可见性,中间状态数据对外部不可见,只有最初状态和最终状态的数据对外可见。
举例:张三给李四转账100元。事务要做的是从张三账户上减掉100元,李四账户上加上100元。一致性的含义是其他事务要么看到张三还没有给李四转账的状态,要么张三已经成功转账给李四的状态,而对于张三少了100元,李四还没加上100元这个中间状态是不可见的。
2.事务的隔离性
若没有事物的隔离性所产生的问题:
(1)
脏读:
一个事务处理过程里读取了另一个未提交的事务中的数据
(2)
不可重复读:
指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了
(3)
幻读(虚读):
幻读的重点在于新增或者删除,同样的条件, 第1次和第2次读出来的记录数不一样
例子:事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
注意:
脏读是某一事务读取了另一个事务未提交的脏数据。幻读和不可重复读都是读取了另一条已经提交的事务。幻读重点在于新增和删除,不可重复读重点在于修改
MySQL数据库为我们提供的四种隔离级别:
(1)
serializable(串行化) :可避免脏读、不可重复读、幻读的发生。
(2)
Repeatable read(可重复读):可避免脏读,不可重复读
(3)
Read committed(读已提交):可避免脏读
(4)
Read uncommitted (读未提交):最低级别,任何情况都无法保证。
注意:
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。
在MySQL数据库中,支持上面四种隔离级别,默认的为
Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为
Read committed(读已提交)级别。
3.Spring事务传播机制
Spring在
TransactionDefinition
接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,
(1)
PROPAGATION_REQUIRED若当前有事务则加入当前事务,若没有则新建一个事务
(2)
PROPAGATION_SUPPORTS若当前有事务则加入事物,若没有则以非事物方式执行
(3)
PROPAGATION_MANDATORY必须以事务方式执行,若没有事务则抛出异常
(4)
PROPAGATION_REQUIRES_NEW新建事务,若当前有事务,则将当前事务挂起。
(5)
PROPAGATION_NOT_SUPPORTED若有事务则将事务挂起
(6)
PROPAGATION_NEVER若有事务则抛出异常
(7)
PROPAGATION_NESTED若有事务则嵌套事务,若没有,则执行类似 PROPAGTAION_REQUIRED的操作
注意:
PROPAGATION_NESTED
与
PROPAGATION_REQUIRES_NEW
区别:
PROPAGATION_NESTED
:嵌套事务不能自己提交,必须通过外层事务提交,若嵌套事务内发生异常,并不会将整个事务回滚,而是回滚到嵌套事务开始前的节点。当外层事务提交或回滚时会带动嵌套事务提交和回滚。
PROPAGATION_REQUIRES_NEW:将启动一个全新的内层事务,外层事务将被挂起,直到内层事务结束,外层事务才能继续执行。内层事务完全独立,不依赖与外层事务,与外层事务没有任何关系。
PROPAGATION_MANDATORY
:不能被非事物的方法调用
PROPAGATION_NEVER
:不能被带事物的方法调用