一.设置Mysql的事务级别
1) my.ini文件中:
# READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ,SERIALIZABLE transaction_isolation = READ-COMMITTED
2) 启动参数指定:
./mysqld --transaction-isolation=READ-COMMITTED
3) 命令行指定:
mysql>set global transaction isolation level READ COMMITTED
命令行的参数列表为:
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
通过命令行设置事务级别之后,需要关闭当前窗口,因为修改后的新参数不会对当前会话生效.mysql中默认的事务级别为"REPEATABLE READ".可以通过"select @@global.tx_isolation;"来查看当前全局的事务级别.
二,事务隔离级别
1) READ UNCOMMITTED: 隔离级别最低,并发能力最高.未提交读(读到未提交),简单来说,就是事务中(或者非事务)可以读取到其他事务已经更新但尚未提交的数据--脏读.也会出现"不可重复读""幻读"等问题. 此事务隔离级别,只会对不同事务中update/select for update等行锁进行"串行化"执行(阻塞),而对于read操作就像"没有事务"一样.
图2 会话2中非事务下read到未提交的数据,且update操作阻塞(因为会话1中的事务update时锁定了id = 1的行)
2) READ_COMMITTED: 已提交读,即只能读取到已经提交的事务所update的数据,会出现"不可重复读","幻读"问题.如果2个并行的事务,其中事务1第一次read时获得一条记录,此后事务2对此记录进行了更改且事务提交,那么此时事务1再次read时,将会获得已经提交的新记录数据,因此为"不可重复的".
3) REPEATABLE_READ: 可重复读,有"幻读"问题;只能读取到其他事务已经提交的数据,且如果当前事务中对某条记录曾近read过,那么此后在事务中多此重复read,将会得到相同的数据,即使此时其他事务已经对此数据进行了更改;由此可见在REPEATABLE_READ隔离级别中,read操作将会产生snapshot,此后多次read只会从snapshot中获取数据;这也是它和"READ COMMITTED"的区别---"READ COMMITEED"不会使用snapshot.
此隔离级别,通常被用在对数据一致性要求较高的环境中.它通常意味着,每个事务将会对read/update选取的行加锁.
4) SERIALIZABLE: 串行化,隔离级别最高.将所有的事务串行化,因此并发能力有效,通常可以理解为事务导致了"表锁".
图5 事务2中对此行进行update,此时update阻塞直到事务1结束.
由此可见,SERIALIZABLE级别通过对事务选取的行加锁的方式(select或者update等),来阻止其他事务对数据的更改:事务1对通过select对id=1的数据加锁,那么事务2尝试update也将阻塞直到事务1结束;此外如果事务1通过update方式对id=1的行加锁,那么事务2对此行select也会阻塞..此隔离级别通过这种方式,严格的杜绝的"脏读""不可重复读""幻读"的发生.(其他隔离级别中,不会出现read行加锁的情况.)
上述各个隔离级别中,如果事务1对id = 1的数据更改,事务2也尝试update时,将会导致事务2阻塞,直到事务1提交;这也是mysql为了避免"更新丢失"的解决方式.不过在SERIALIZABLE级别中还有特殊的情况.
"脏读": 读取了一个尚未确定的值,通常是事务中(或者在READ UNCOMMITTED隔离级别中的非事务)读取了其他事务尚未提交的值.
"不可重复读": 脏读的一种表现,通常为多个事务并行操作时发生.
"幻读": 多个事务并行操作时,当读取的数据位多行数据时(range),一个事务中多次读取发生数据条数不一致的情况.