一.事务的四大特性(ACID)
1.原子性(atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
比如:
以银行转账为例,一次转账包含两条update更新语句,所以一个事务不一定只执行一条SQL语句,对于银行转账这件事,只有“11111”账户划走1000,“22222”账户收到这1000,才算这个事务完成(一次转账完成)。
update t_balance set 余额=余额-1000 where card_id="11111";
update t_balance set 余额=余额+1000 where card_id="22222";
2.一致性(consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后必须处于一致状态。
比如:
以银行转账为例,转账前两个账户金额总和为20000,转账之后总额还是20000,无论怎么转账,前后总和保持一致。
3.隔离性(Ioslation)
隔离性是指当前多个用户并发访问数据库的时候,数据库为每一个用户开启事务,其中某一个事务不能被其他事物操作所干扰,多个并发事务之间要相互隔离,即要达到这样效果:对于任意两个并发事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始执行
4.持久性(Durability)
持久性是指一个事务一旦提交,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统中遇到故障的情况下也不会丢失提交事务的操作。
二.数据库的四种隔离级别(对应事务的隔离性)
1.串行化(Serializable)
可以避免脏读,不可重复读和幻读的发生
2.可重复读(repeatable read)
可以避免脏读,不可重复读的发生
3.读已提交(read committed)
可以避免脏读的发生
4.读未提交(read uncommitted)
最低级别,任何情况下都可能发生
以上四种隔离级别,最高等级是串行化,最低等级是读未提交,隔离级别越高,执行效率越低
MySQL的默认隔离级别是可重复度(repeatable read)
oracle的默认隔离级别是读已提交(read committed),它只支持串行化和读已提交级别。
因为有了并发事务,多个事务同时执行,根据数据库的隔离级别,就会产生以下问题:
1.脏读:指在一个事务处理过程中读取另一个未提交事务的数据。
以银行转账为例:
update t_balance set 余额=余额-1000 where card_id="11111";
update t_balance set 余额=余额+1000 where card_id="22222";
在执行完第一个更新语句时,但是还没有执行第二个更新语句 ,这是另一个事务在读取t_balance表的数据,余额被减,通知用户余额减过了,还没有执行第二条更新语句就回滚了,此时已经提示过余额被减。这个情况就是脏读。
2.不可重复读:针对数据库中某个数据,一个事务范围内多次查询却返回不同的数据值,这是由于在查询的间隔,被另一个事务把数据修改并提交了。
比如:
事务T1在读取某一个数据,而事务T2修改了这个数据,并且提交了事务,事务T1再次读取这个数据,就与上一次T1事务读取的值不同,发生不可重复读
不可重复读和脏读区别:
脏读是某一个事务读取了另一个事务未提交的数据
不可重复读是某一个事务读取了上一个提交的数据
注意:在某些情况下,不可重复读不是问题,无论数据被改多少次且提交,只需要获得最后提交的数据即可。
3.幻读:事务非独立执行时发生的一种现象
比如:
事务T1对一个表中的所有行的某个数据项做了从“1”修改数据为“2”的操作,这时事务T2又对这个表添加一行数据,而这行中指定的列的数据项是“1”,并且提交给数据库,这时操作事务T1的用户查询此数据表,就会发现有一行没有从“1”修改到“2”,此种情况就是幻读。
幻读和不可重复读都是读取了另一个已经提交的事务,脏读是读取另一个未提交的事务数据,不可重复读查询的是同一个数据项,而幻读针对是一批数据的整体中的某个数据项。
三.如何设置隔离级别
1.如何在MySQL中设置隔离级别
//在MySQL的黑白界面中
set tx_isolation='隔离级别名称'
2.在Java中设置隔离级别
try{
Connection con=null;
//设置数据库的隔离级别,只对当前连接有效
con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
con.setAutoCommit(false);//开始事务
...
con.commit();
}catch(Exception e){
con.rollback();
e.printStaceTrace();
}