1、事务的概念:指的是一个操作序列,在操作序列中,多个操作要么全部执行成功,要么全部执行失败,是一个不可分割的逻辑工作单位;
2、事务的特性(ACID)
原子性: 多个操作是不可分割;
一致性: 多个操作要么全部成功,要么全部失败;
隔离性: 多个事务是互不干扰的;
持久性: 一旦提交到数据库,持久保持,不丢失数据;
3、命令实战:
begin; 或START TRANSACTION; -- 开启事务
操作的sql语句,如update admin set account = 9000; -- 执行操作语句
commit; 或者 rollback; -- 提交或回滚
如提交:
begin;
update admin set account=9000 where id=1;
update admin set account=11000 where id=2;
commit;
或回滚
begin;
update admin set account=9000 where id=1;
update admin set account=11000 where id=2;
rollback;
其中begin也可以换成:START TRANSACTION;
4、在回滚和提交之前,sql语句实际上操作的是缓存的数据,在回滚和提交的时候才真正把数据清除或序列化到磁盘;
5、多个事务并发问题:
在多线程中,多个线程操作一个数据会引发线程安全问题;在mysql事务中也一样,多个线程操作去操作同一条数据,也会引发操作事务并发问题;
多事务并发问题主要有以下三种情况(SQL92标准中就定义了这三种,基本上也只有这三种):
(1)脏读:读到未提交的事务
a、场景:
事务A开启事务,事务B开启事务
事务A执行查询,事务B进行修改
事务A再进行查询,
查到事务B未commit的数据,此时若事务B进行回滚
则事务A查到了脏数据;
b、如何解决:将事务隔离级别设置为READ COMMITED,读已提交的事务;
(2)不可重复读(针对update操作)
a、 场景:
事务A开启事务,事务B开启事务;
事务A进行查询,事务B进行数据的update操作,事务未提交
事务A进行再次查询,没查到脏数据了(解决脏读问题)
事务B提交数据
事务A进行第三次查询,则会查到事务B 提交的数据
当事务A在同一个事务中,进行三次查询,就会出现第三次查询的结果和第一次查询的结果不一致的情况,称为不可重复读;根据 事务的原子性原则,一个事务不管查多少 次,查询的结果应该是一样的
b、如何解决?事务隔离级别设置为REPARIABLE READ,
原因:因为不可重复读主要发生在同一个事务对同一条数据(主要是被修改的数据)的多次查询结果不一致的问题,那么可以针对该条数据进行加锁,且加行锁即可;
(3)幻读:针对范围查询,新增或删除数据
a、场景:
事务A开启事务,事务B开启事务
事务A进行范围查询id>5,得到结果=4,此时事务B新增或删除一行数据,并提交事务;
事务A进行二次查询时,id>5,得到额结果却是5,事务A在同一个事务里面2 次查询的结果不一致就是幻读问题;
由于事务隔离为REPARIABLE READ,用了行级锁,因此对新增或删除数据无效
b、如何解决?设置事务隔离级别为:SERIALIZABLE
原理:加表锁,但是会影响性能
7、mysql的Innordb存储引擎默认是REPEATABLE READ的事务隔离级别;解决了脏读和不可重复读,同时兼顾并发性能;
8、事务的隔离级别:
read uncommitted:读未提交的事务,级别最低,在这种隔离级别下,会发生脏读,也会发生不可重复读和幻读;
read committed: 读已提交的事务,解决了脏读的问题,会出现不可重复读和幻读;
repeatable read:可重复读,通过加行级锁,解决了不可重复读的问题,仍然会出现幻读;
serializable: 可串行化,通过加表锁,解决了幻读问题;
9、设置事务隔离级别实战:
查看和设置事务隔离级别:
SHOW VARIABLES LIKE '%transaction_isolation%';
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
注意:在设置完事务隔离级别后,在当前回话,再查询事务隔离级别,数据不会有变化,需要重新打开回话才能查到新设置的数据;
重新打开一个回话,查看事务隔离级别是否设置成功