mysql事务
一个或者一组sql语句组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行。多条sql语句构成执行单元,单元中每个mysql语句都是相互依赖的。当单元中的某条sql语句失败的话,这个单元都会回滚。受影响的数据将回到事务开始的状态。
1、事务的ACID属性
原子性:是指事务是一个不可分割的工作单位,事务中的操作要么全部发生,要么全部不发生。
一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态。
隔离性:指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
持久性:一个事务一旦被提交,她对数据库中数据的改变是永久的。其他事务或操作的故障和数据库的故障都不能对其有任何影响。
2、原子性实现原理
undo log用来实现事务的原子性。在操作任何事务之前,首先将数据备份到一个地方,存储数据备份的地方称之为Undo log。然后继续数据的修改。如果出现了财务或者用户执行回滚语句,系统就可以利用undo log中的备份将数据恢复到事务开始之前的状态。
undo log存储的是逻辑日志,而不是真正的数据,可以理解为:
1、delete一条数据时,undo log就记录一条对应的insert记录。
- insert一条数据时,undo log就记录一条对应的delete记录。
- update一条数据时,undo log就记录一条相反的update记录。
MYsql的InnoDB存储引擎中,undo log还可以用来实现多版本的并发控制,例如如果会话1对表1进行插入或修改操作,但未提交,会话2对表1进行查询,此时会去undolog读取之前版本的数据。
3、持久性实现原理
和undolog相反,Redo log存储的是新数据的备份。在事务提交前,只要将Redo log持久化即可,不需要将数据持久化。当系统奔溃时,虽然数据没有持久化,但是Redolog已经持久化,系统可以根据Redo log的内容,将所有数据恢复到最新的状态。
4、事务的创建
隐式事务:事务没有明显的开启和结束的标记,比如insert、update、delete语句
显示事务:事务有显示的开始和结束的标记。步骤如下.
- 先设置自动提交功能为禁用。set autocommit=0。
- 开启事务:start transaction可选。
- 编写事务中的sql语句,单条或者多条。
- 结束事务,commit。rollback回滚事务。用java通过JDBC调用mysql时,可以用try-catch捕获到插入异常时,catch里面写回滚语句。
5、事务并发问题
对于同时运行的多个事务,这些事务访问数据库中相同的数据时,如果没有采取相对于的隔离机制,就会导致各种并发问题。
- 脏读:对于两个事务T1和T2,T1读取了已经被T2更新但还没被提交的字段,之后若T2回滚,那么T1读取到的数据就是错误无效的。正常来说,应该是T2提交后T1才有可能被读取到新数据,那T2提交后T1能否读取到新数据,就涉及到不可重复读的问题了。
- 不可重复读:对于两个事务T1和T2,T1读取了一个字段后。然后T2提交更新了该字段,T1未提交,再次读取同一字段,发现值不同了。正常应该是T1未提交,再次读取 值是一样的,T1提交后再开启通过事务读取数据,这时数据才会改变。
- 幻读:事务T1和T2,T1从表中读取一个字段,然后T2在该表中插入了一些新的行,如果T1再次读取同一张表,那么可能会多出几行。脏读和幻读差别是一个是数据的更新,一个是数据的插入删除。
那么有了这么多并发问题后应该怎么办?应该用隔离级别将事务进行隔离。不同的隔离级别可以解决不同的并发问题。
6、mysql隔离级别
.1、读未提交(read uncommitted):允许其他事务读取未被其他事务提交的变更(update)。三种并发问题都会出现。
- 读已提交(read commitred,oracle默认的隔离级别):只运行读取其他事务已提交的变更。可以避免脏读,但是避免不了不可重复读,和幻读。读取的数据为最近持久化的数据版本。
- 可重复读(repeatable read,mysql默认隔离级别):确保事务T1可以多次在一个字段中读取相同的值,无论其他事务怎么更改这个字段的值,只要T1没有被提交,T1就可以一直读取这个字段的相同值。可避免脏读、不可重复读,不可避免幻读。读取的数据为开启事务当前的数据历史版本。
- 串行化(serializable):确保事务可以从一个表中读取相同的行,在这个事务期间,禁止其他事务对这个字段进行更新、插入、删除操作。三种并发问题都能避免,但是性能非常低。
- 常用命令:
查看隔离级别:select @@transaction_isolation
设置隔离级别:set session|global transaction isolation level隔离级别
7、MVCC
MVCC指的是使用读已提交和可重复读的这两种隔离级别的事务在执行普通的select操作时访问记录的版本链过程。可以使不同事务的读写操作并发执行,提高性能。读已提交和可重复读的这两种隔离级别一个很大的不同就是:生成的ReadView的实际不同,读已提交每一次普通的select操作都会生成一个ReadView,而可重复读只在第一次普通的select操作强生成一个ReadView,之后的查询都用这个ReadView。ReadView不同,读取的数据版本就不同。
下面是某条记录的版本链,数据中有包含事务ID和指向版本数据的回滚指针,通过回滚指针可以访问到之前版本的历史记录。