事务处理机制在程序开发过程中有着非常重要的作用,它可以使整个系统更加安全,保证在同一个事务中的操作具有同步性
一,事务的概念
现实生活中,人们经常会进行转账操作,转账可以分为两部分,转入和转出,只有这两部分都完成才认为转账成功。在数据库中,这个过程是使用两条语句来完成的,如果其中任意一条语句出现异常没有执行,则会导致两个账户金额不同步,造成错误。
为了防止上述情况的发生,MYSQL中引入了事务,所谓事务就是针对数据库的一组操作,它可以由一条或多条SQL语句组成,同一事务的操作具有同步的特点,如果其中一条语句无法执行,那么所有的语句都不会执行,也就是说,当事务中的语句,要么都执行,要么都不执行。
创建chapter06数据库:
进入chapter06数据库:
创建account表并插入相应的字段;
给account表添加相应的数据:
查看account 表
开启事务,将a账户的100元钱转给b账户,并提交事务;
查看account表数据
二,事务的提交
开启一个事务,使用update语句实现又b账户向a账户转100元钱的功能
查看account表:
退出数据库重新登录查询account表:
可以看出,转账操作并没有成功,因为没有提交事务就退出数据库了,由此可以得出事务中的语句不能自动提交。
下面为事务提交并且退出数据库,再登录查看,可以看出成功了
三,事务的回滚
开启一个事务,通过update语句将a账户的100元转给b账户,并查询结果;
a账户成功给b账户转账100元钱,此时a账户不能给b账户转账,由于事务还没有提交,就可以将事务回滚,如下是回滚后查询的结果:
四,事务的隔离级别
1,(read uncommitted)脏读
开启a,b两个账户(数据库)
设置b账户的隔离级别并查看
为了证明脏读的情况,首先在b账户中开启一个事务,并在该事务中查询当前账户的余额信息;
在a账户中开启一个事务,并在当前窗口中执行转账功能,并查询b账户;
从查询结果可以看来,a账户已经成功给b账户转账100元钱,这是由于b账户的事务隔离级别较低,由此读取了a账户中还没提交的内容,出现脏读的情况,上述情况演示完,之后,还需将a账户的事务回滚,将b账户中的事务提交。
为了防止脏读现象的发生,需要将b账户的隔离级别设置为read commited(读提交),该级别可以避免脏读。
为了说明没有脏读的现象,首先b账户开启了一个事务,并在该事务中查询各账户的余额信息;
a账户重新开启一个事务,并实现转账功能:
通过比对两次结果可以发现,b账户在同个事务中的查询结果是一致的,并没有查询到a账户中未提交的内容,由此可以说明read committed 隔离级别可以避免脏读,最后分别将a账户的事务和b账户中的事务回滚。
2,(non-repeatable read) 不可重复读
首先在b账户开启一个事务,然后在当前事务中查询各账户的余额信息,查询结果如下:
在a账户中不用开启事务,直接使用update语句执行更新操作并查看即可:
当a账户中的更新操作执行成功后,在b账户再次查询各账户的余额:
对比两次查询的结果看出是不一致的,实际上这种操作是没错的,但是银行统计报表时,这种情况是不符合需求的,因为我们并不希望在一个事务中看到查询结果不一致,这就是不可重复读。上述情况演示成功后,还要将b账户的事务提交:
为了防止重复读的情况出现,可以将该事务的隔离级别设置为repeatable read(可重复读):
在b账户中,重新开启一个事务,然后使用select语句查询当前账户的余额:
在a账户中不开启事务,直接使用update语句执行更新操作,并查询:
执行成功后,再次查询账户的余额信息:
演示成功后,将b账户的事务提交;
3,(phantom read)幻读
将b账户的隔离级别设置更低,设置为read committed;
首先在b账户中开启一个事务,然后在当前事务中查询账户的余额信息:
在对a账户添加操作之前,使用select语句查看当前a账户中的信息,执行语句如下所示:
接下来对a账户添加操作,a账户不开启事务,执行添加操作即可:
当a账户执行成功后,可以在b账户中再次查询账户的余额信息:
防止幻读。可以将b账户的隔离级别设置为repeatble read:
4,(serializable)可串行化
事务的最高隔离级别,它在每个读的数据行上加上锁,使不能相互冲突,因此导致大量的超时现象;
首先将b账户的隔离级别设置为serializable:
在b账户中开启事务,然后使用select语句查询各个账户的余额信息:
当b账户中的事务提交成功后,a账户中的添加操作才能执行成功,并输出如下语句;
从上述情况可以看出,如果一个事务使用serializable(可串行化)隔离级别时,在这个事务没有被提交之前,其他线程只能等到当前操作完成之后,才能进行操作。这样非常耗时,而且会影响数据库的性能,通常情况下是不会使用这种隔离级别的。