1、并发下事务会产生的问题:
脏读:
事务A读到了事务B还没有提交的数据: 比如银行取钱,事务A开启事务,此时切换到事务B,事务B开启事务-->取走100元,此时切换回事务A,事务A读取的肯定是数据库里面的原始数据,因为事务B取走了100块钱,并没有提交,数据库里面的账务余额肯定还是原始余额,这就是脏读。
不可重复读
在一个事务里面读取了两次某个数据,读出来的数据不一致
事务A开启事务-->查出银行卡余额为1000元,此时切换到事务B事务B开启事务-->事务B取走100元-->提交,数据库里面余额变为900元,此时切换回事务A,事务A再查一次查出账户余额为900元,这样对事务A而言,在同一个事务内两次读取账户余额数据不一致,这就是不可重复读
幻读:
在一个事务里面的操作中发现了未被操作的数据。
事务A开启事务-->修改所有学生当天签到状况为false,此时切换到事务B,事务B开启事务-->事务B插入了一条学生数据,此时切换回事务A,事务A提交的时候发现了一条自己没有修改过的数据,这就是幻读,就好像发生了幻觉一样。
幻读出现的前提是并发的事务中有事务发生了插入、删除操作。
2、事务隔离级别
事务隔离级别,就是为了解决上面几种问题而诞生的。虽然事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡。设置最优隔离级别
读未提交: Read uncommitted:
一个事务还没提交时,它做的变更就能被别的事务看到。。这个级别的隔离机制无法解决脏读、不可重复读、幻读中的任何一种,因此很少使用
读已提交: READ_COMMITED(数据库的默认隔离级别,即默认解决脏读问题)
一个事务提交之后,它做的变更才会被其他事务看到。sql执行的时候创建视图。锁定正在读取的行。只能防止脏读
重复读取:REPEATABLE_READ
重复读就是,事务在启动时看到的数据,再反复读取也是原数据。事务启动时创建一个视图。即在数据读出来之后加锁,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,
这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决,锁定所读取的所有行
串行化:
最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务。解决所有事务并发问题。但是效率最低。表级锁
3、设置事务隔离级别:
查看事物隔离级别:
select @@tx_isolation;
设置事务隔离级别:
set tx_isolation='事物隔离级别名称';
4、事务隔离的实现原理(乐观锁):
如果所有的事务都排队进入数据库操作,就没有什么隔离级别可言。做到事务的隔离利用
InnoDB的MVCC(多版本并发控制):同一条记录在系统中可以存在多个版本。记录在undolog日志中
这样查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。不用等待另一个事务释放锁