事务是什么
一个或一组sql语句组成的一个执行单元,这个执行单元里面的sql要么都执行,要么都不执行
事务的属性
- 原子性
原子性指事务时一个不可分割的工作单位,事务中的操作要么都执行要么都不执行
- 一致性
从一个正确的状态,迁移到另一个正确的状态.什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态.
- 隔离性
事务的隔离性是指一个事务的执行不能被其他事务干,即一个事务内部的操作以及使用的数据对并发的其他事务时隔离的,并发执行的各个事务之前互不干扰
- 持久性
事务一旦提交,它对数据库中的数据的改变就是永久性的
事务的创建
- 隐式事务:
事务没有明显的开启和结束的标记,例如insert,update,delete语句
- 显式事务:
前提是先关闭自动提交(当前会话有效):set autocommit = 0
步骤一:开启事务
start transaction;
步骤二:编写事务中的sql语句(select,insert,update,delete)
第三步:提交或者回滚
提交 commit 回滚 rollback
事务并发情况下没设置隔离级别产生的问题
- 脏读
对于两个事务T1、T2,T1读取了已经被T2更新但还没提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的
- 不可重复读
对于两个事务T1、T2,T1读取了一个字段,然后T2更新了该字段之后,T1再读取一次该字段,值不相同
- 幻读
对于两个事务T1、T2,T1从一个表中读取了一个字段,然后T2再在该表中插入一些新数据,之后T1再次读取同一个表,就会多出几行
事务的隔离级别
一个事务于其他事务隔离的程度成为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越高,但是并发性能越弱
隔离级别测试
- READ UNCOMMITTED
原始表,只有一个数据 id为1,name为张三
先打开打开两个会话 都设置隔离级别为 READ UNCOMMITTED 并且开启事务,然后第一个会话输入操作命令:修改id为1的姓名,新增一条name为王五的数据
第一个事务修改数据,但是不提交也不回滚
第二个事务读数据,可以看到事务未提交未回滚的数据都已经被读到了
第一个事务回滚数据 rollback
第二个数据再次读数据(出现了所有的并发下的问题(脏读,幻读,不可重复读)
- READ UNCOMMITTED
先打开打开两个会话 都设置隔离级别为 READ COMMITTED 并且开启事务,然后第一个会话输入操作命令:修改id为1的姓名,新增一条name为王五的数据
第一个事务修改数据,但是不提交也不回滚
第二个事务读数据,可以看到读取的还是之前的数据,未提交的数据无法读取到
第一个事务提交数据 COMMIT
第二个数据再次读数据(可以有效避免脏读,但是不能避免不可重复读和幻读,因为这个事务还没结束,读取到的数据前后不一致)
- REPEATABLE READ
先打开打开两个会话 都设置隔离级别为 READ COMMITTED 并且开启事务,然后第一个会话输入操作命令:修改id为1的姓名,新增一条name为王五的数据
第一个事务修改数据,但是不提交也不回滚
第二个事务读数据(读取到原本的数据,未提交的数据无法读取到)
第一个事务提交数据 COMMIT
第二个数据再次读数据(读取的还是原来的数据,已经成功避免了脏读,不可重复读)
明显看到现在独到的数据只有原始的一条数据,但是我们这时候去修改数据却修改了两条信息,所以还是没有避免幻读
当我们提交或回滚(结束)事务,再次查询,才可以读到最新数据
- SERIALIZABLE
最高的隔离级别,能有效避免事务并发情况下的各种问题,通过禁止另一个事务增删改的方式,但是效率非常低下
mysql和oracle的隔离级别区别
oracle支持两种隔离级别:READ COMMITED、SERIALIZABLE,默认是 READ COMMITED
mysql支持四种隔离级别:(以上四种),默认是REPEATABLE READ
回滚的保存点
通过SAVEPOINT设置一个保存点。当配合rollback命令的时候 会保存SAVEPOINT之前的操作。如下面代码,当回滚到a的时候,id为1的数据已经被删除,而其他的不会执行成功
set autocommit = 0; #关闭自动提交
START TRANSACTION; #开启事务
SELECT * FROM bsl;
DELETE FROM bsl WHERE id =1;
SAVEPOINT a;
DELETE FROM bsl WHERE id =4;
rollback to a;
truncate在事务中不支持回滚,如果使用truncate清空一个表,那么即便回滚了,表数据还是会被清空完毕