事务(Transaction)
指一组操作,里面包含许多个单一的逻辑,只要有一个逻辑没有执行成功,那么都算失败,所有的数据回归到最初的状态(回滚)
- 事务用处
为了确保逻辑的成功。例:银行转账
使用代码方式演示事务
代码里的事务只要是针对链接
- 步骤:
- 通过conn.setAutoCommit(false)来关闭自动提交的设置
- 提交事务conn.commit()
- 回滚事务 conn.rollback()
事务的特性ACID
- 原子性
事务中包含的逻辑不可分割 - 一致性
事务执行前后数据完整 - 隔离性
事务在执行期间不应该受到其他事务的影响 - 持久性
事务执行成功后数据应该持久保存在磁盘上
事务的安全隐患
隔离级别
-
Read Uncommitted【读未提交】
一个事务可以读取到另一个事务还未提交的数据,会引发“脏读”,读取到的是数据库内存中的数据,而并非真正磁盘上的数据
引发:脏读 -
read Committed【读已提交】
只能读取到其他事务已经提交的数据,那些没有提交的数据是读不出来的,但是这回造成一个问题是:前后读取到的结果不一样,发生了不可重复。所谓的不可重复,就是不能执行多次读取,否则出现结果不一
解决:脏读,引发:不可重复读 -
Repeatable Read【重复读】
MySQL默认的隔离级别
可以让事务在自己的会话中重复读取数据,并且不会出现结果不一样的状况,即使其他事务已经提交了,也依然还是显示以前的数据
解决:不可重复读和脏读 没有解决:幻读 -
Serializable【可串行化】
最高级事务级别,可解决之前三个问题,但效率较低,比较少用
如果有一个连接的隔离级别设置为了串行化,那么谁先打开了事务,谁就有了先执行的权利,谁后打开事务,只能等着前面那个事务提交或者回滚,才能执行mysql:默认隔离级别:可重复读
oracle:默认隔离级别:读已提交效率划分:
读未提交 > 读已提交 > 可重复度读 > 可串行化
按拦截程度:
可串行化 > 可重复读 > 读已提交 > 读未提交
不考虑隔离级别设置,会出现以下问题
- 读
- 脏读
一个事务读到另外一个事务还未提交的数据 - 不可重复读
前后多次读取,数据内容不一致。读取了其他事务更改的数据,针对update操作 - 幻读
前后多次读取,数据总量不一致。读取了其他事务新增的数据,针对insert操作
- 写
丢失数据
- 如果不考虑隔离性,也会产生写入数据的问题,这一类的问题叫丢失更新的问题。
- 例如:两个事务同时对某一条记录做修改,就会引发丢失更新的问题。
- A事务和B事务同时获取到一条数据,同时再做修改
- 如果A事务修改完成后,提交了事务
- B事务修改完成后,不管是提交还是回滚,如果不做处理,都会对数据产生影响
- 解决方案有两种
-
悲观锁
- 采用的是数据库提供的一种锁机制,如果采用做了这种机制,在SQL语句的后面添加 for update 子句
- 当A事务在操作该条记录时,会把该条记录锁起来,其他事务是不能操作这条记录的。
- 只有当A事务提交后,锁释放了,其他事务才能操作该条记录
-
乐观锁
- 采用版本号的机制来解决的。会给表结构添加一个字段version=0,默认值是0
- 当A事务在操作完该条记录,提交事务时,会先检查版本号,如果发生版本号的值相同时,才可以提交事务。同时会更新版本号version=1.
- 当B事务操作完该条记录时,提交事务时,会先检查版本号,如果发现版本不同时,程序会出现错误。