数据库事务的复习笔记

来源:互联网 发布:java json双引号转义 编辑:程序博客网 时间:2024/06/11 17:41
什么是事务:
专业术语:事务(Transaction)是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全的不执行。
白话:事务就是指一个整体,这个整体里面的执行操作(就比如软件开发中对数据库的多条操作的代码)要么全部都要执行完,要不然其中一处没有成功执行那么这个整体里面的所有执行操作都不能成功执行。举个栗子:小明过生日,小明爸爸用微信给小明转了250,那么在微信服务器端就要对数据库的数据执行多个操作后来完成这个用户的行为,其中就包括基本的两个操作小明爸爸的账户里面要减去250,小明的的账户里面要增加250,那么这两个操作就是一个完整的事务,要么都执行成功,要么都不执行,不能出现小明爸爸账户的钱被减少了,而小明的账户缺没有增加余额这样的情况

事务的四大特性:
(1)原子性
原子性是指事务包含对于数据的所有操作要么全部执行成功,要么全部失败进行回滚,也就说如果操作成功,就更新到数据库,如果失败就不能对数据库有任何影响,而不允许某些操作成功了而某些操作失败还继续更新到数据库,例如经典的A给B转账的例子,从A转账更新自己的余额到B接受到转账更新自己的余额的整个过程,每一个步骤都要执行成功,而不能存在A转账了但B没有收到的情况。
(2)一致性
一致性是指事务在对数据库进行一系列操作后,必须使数据库是从一个一致性的状态变换到另一个一致性的状态,也就是说事务对数据库进行操作之后,依然要保持数据处于一致性的状态,例如同同样的一个例子,A和B两个人的总金额为5000,那么不管他们之间如何转账(也就对数据的一系列操作),最终他们两个人的总金额还是不变的,这就是事务的一致性
(2)隔离性
隔离性是指多个并发事务在对相同的数据(这里可以指同一张表)进行操作的时候,这些并发事务是相互隔离的,它们之间的操作不能干扰到其它事务。例如存在两个并发的事务T1和T2,不管其中的哪一个事务,在它看来另一个事务要么在它之前完成操作,要么在它之后操作,而不会更和它并发的执行。这里也就引发出事务的隔离性级别的内容,下面有介绍到

(2)持久性
持久性是指一个事务对数据成功操作之后并提交了,那么在数据库的更新就是持久性的了,即便是数据库系统遇到故障了也不会丢失提交事务的操作



在介绍事务隔离级别之前要明白他们出现的原因,由于存在多个用户在同一时间内发送对数据的操作请求,也就是并发,这样的话就会开启多个并发事务对数据库进行操作,这里就存在并发时常见的问题获取的数据的准确性,那么数据库就是通过事务的不同隔离级别来解决并发操作所存在的问题。

事务的隔离性级别:
如果不考虑事务的隔离性,会发生脏读、不可重复读和幻读
(1)脏读
脏读是指一个事务(T1)对某个数据进行更新等操作的时候,还没有执行事务提交之前,出现另一个事务(T2)也对这个数据进行了读写等操作,那么T2本身读的数据就是不准确的了,这就是读了脏数据,也就是脏读
(2)不可重复读
不可重复读是指在一个事务(T1)范围内前后对某个数据进行了多次查询,但是前后查询的数据出现了不同的结果,这是由于在这个前后的时间段中,这个数据被另一个事务(T2)修改过并且提交了事务,所以就存在查询前后出现数据结果不同的情况
(3)虚读(幻读)
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
  幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

既然出现了这些情况,就知道了事务隔离基本存在的原因了。那么我们来看下事务的隔离级别有哪些:

以MySQL的事务隔离级别分析(级别由低到高):
①Read uncommitted(读未提交)->以上任何情况都无法保证不会发生
②Read committed(读已提交)->可避免脏读的发生。(其实如果理解上面的三种出现的原因后,就很好明白这些隔离级别的功能了)
③Repeatable read(可重复读)->可避免脏读和不可重复读的发生
④Serializable(串行化)->可避免上述三种情况的发生


在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读),为什么会出现四种不同的隔离级别呢?为什么不直接用最高级别Serializable(串行化),这样不就不会出现错误了吗?之所以出现不同的隔离级别,还是根据具体的实际情况来定的,这里还涉及到并发的过程,就举个例子,如果对一块数据(或者说数据库中的一张表的数据)只允许读而不允许更新的话,那么就比必要设置高级别的隔离性,用最低级别的就可以了,原因之一是级别越高的话执行的效率就越低,这个很好明白,并行处理客户请求比串行处理大量的请求要快的多,原因之二就是读操作并不涉及对这些数据有更新的操作,所以数据是不会改变的,就不会存在上述的异常情况,也就没有必要设置高级别的隔离性,所以总的来说,根据实际情况(业务需求)来选定设置哪种隔离级别。

事务隔离级别的设置:
说了什么是事务,事务的四大特性、不同的隔离级别以及对应的可能参数的异常,那就应该知道如何根据实际的业务需求来设置事务的隔离性
在讲述如何设置事务的隔离性之前,必须要明白隔离级别的设置只是对当前链接有效,对于MySQL使用的命令行窗口而言,一个窗口就是一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说(说白了就还是我们用代码创建连接数据库的时候),一个Connection实力对象对应一个链接,也就是对应它自己的隔离界别

在MySQL命令行中:
查询当前链接的事务隔离级别的:select@@tx_isolation
设置事务隔离界别:set[glogal | session]transactionisolationlevel 隔离级别名称
set tx_isolation=’隔离级别名称;’

在使用JDBC的时候(首先要记住的是在设置隔离级的时候一定要在开启事务之前):
(这里就不阐述JDBC相关的创建数据库连接、编写事务的过程了,具体可以参考http://blog.csdn.net/lijizh1013/article/details/7964992或者其它博客
在JDBC中设置事务隔离级别,应该在调用Connection实例对象的setAutoCommit(false)方法之前,调用Connection实例对象的setTransactionIsolation(level)就可以设置当前所创建的链接的事务隔离级别了,其中的level,就是上面提到的四种,Connection对象的字段(具体代码就不呈上了,很简单的):


参考地址:
https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%8B%E5%8A%A1/9744607?fr=aladdin
http://www.cnblogs.com/fjdingsd/p/5273008.html

原创粉丝点击