问题一:什么叫数据库的事务?
数据库的事务表示一连串的数据库执行语句,这一连串的数据库执行语句可以构成一个数据库事务。
问题二:如何标示一个事务的开始和结束?
当你建立了一个数据库的链接,那就表明一个事务的开始。那么第一次事务的结束,又如何标示呢?有两种方案:显示事务操作和隐式事务操作。
显示事务操作:显示的调用数据库命令或者各种语言对数据库事务支持的编程接口,来提交一个事务的完整执行(即commit),或者撤销一个事务的已经执行的步骤(即rollback),或者设置一个阶段性的事务执行保存点(即savepoint,一旦设置savepoint,rollback只能回到保存点)。
隐式事务操作包括:隐式提交和隐式撤销。
隐式提交:由系统自动完成事务的提交,无需用户关心。当用户正常退出sql或者执行create、drop、grant、revoke等命令时会发生事务的自动提交。
隐式撤销:由系统自动完成事务的撤销,无需用户关心。当用户异常退出sql或者系统故障时,会发生事务的自动回退操作。
还有一种情况就是将系统的autocommit设置为on(默认是off),这样子每当执行一条delete、update、insert语句都会自动提交一次。
综上所述,每一次一个事务commit或者rollback都标示一个事务的结束,下一个事务的开始。只不过事务的提交或者撤销有显示和隐式之分而已。
下图1.1所示表示一个数据库事务的生命周期:
问题三:事务的ACID的含义是什么?
事务的ACID字面含义是原子性、一致性、隔离性、持久性。
原子性(Atomic):标示一个事务的所有执行语句要么全部执行,要么全部不执行。全部不执行的含义是当某一个执行语句执行失败,则需要rollback到事务执行的初始状态。
一致性(Consistency):指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。例如对于银行转账事务,不管事务成功还是失败,应该保证事务结束后Accounts表中两人的存款总额不变。读一致性也是数据库一致性的重要方面,
读一致性也是数据库一致性的一个重要方面,在实际中,我们会遇到这种情况:我们对一个表中的某些数据进行了更新操作,,但是还没有进行提交,这时另外一个用户读取表中数据.这个时候就出现了读一致性的问题:到底是读什么时候的数据呢?是更新前的还是更新后的?在DBMS中设有临时表,它用来保存修改前的值,在没有进行提交前读取数据,会读取临时表中的数据,这样一来就保证了数据是一致的.(当前用户看到的是更新后的值)
但是还有一种情况:用户user1对表进行了更新操作,用户user2在user1还没有进行提交前读表中数据,而且是大批量的读取(打个比方:耗时3分钟)而在这3分钟内user1进行了提交操作,那又会产生什么影响呢?这个时候怎么保证读写一致性呢?这个时候DBMS就要保证有足够大的临时表来存放修改前的数值,,以保证user2读取的数据是修改前的一致数据.然后下次再读取时候就是更新后的数据了
隔离性(Isolation):多个事务的并发执行,一个事务的执行不能影响另外一个事务。由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
持久性(Durability):已提交的事务对数据库的修改必须永久保存在数据库中。
问题四:事务的隔离性是如何实现的?
很显然事务的隔离性有点类似多线程编程中的线程间同步如何实现。也就是对临界区的互斥访问必须有一套机制保证当前只有一个线程进入临界区。linux多线程间的同步时才用锁的机制,那么事务的隔离性其实也是差不多的,也是采用锁的机制。
出于性能考虑,许多数据库允许使用者选择牺牲隔离属性来换取并发度,从而获得性能的提升。SQL定义了4种隔离级别:
Read Uncommitted:
直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别的事务可以读到这个改变.这是很不安全的.
Read Committed:
直译就是"读提交",意思就是语句提交以后即执行了COMMIT以后别的事务就能读到这个改变.
Repeatable Read:
直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.
Serializable:
直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行.
隔离级别的降低可能导致读到脏数据或者事务执行异常,例如:
Lost update:
两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。
Dirty Reads:
一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。
假设A向B转帐100元,A在一台电脑上开启事务执行如下2步操作,向B存入100元,并把自己的钱减少100元:
1.update account set money=money+100 while name=‘b’;
2.update account set money=money-100 while name=‘a’;
当第1步执行完,第2步还未执行,A未提交时,此时B查询自己的帐户就会发现自己多了100元钱,以为A转了100元。如果A等B走后再回滚,B就会损失100元
Non-repeatable Reads:
一个事务对同一行数据重复读取两次,但是却得到了不同的结果。
例如银行想查询A帐户余额,第一次查询A帐户为200元,此时A向帐户内存了100元,银行此时又进行了一次查询,此时A帐户为300元了,银行可能就会很困惑,不知道哪次查询是准的。和脏读的区别是,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。
很多人认为这种情况就对了,无须困惑,当然是后面的为准。我们可以考虑这样一种情况,比如银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个事务中针对输出的目的地,进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了。
Second lost updates problem:
无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。
Phantom Reads:
事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。
如丙存款100元未提交,这时银行做报表统计account表中所有用户的总额为2700元,然后丙提交了,这时银行再统计发现帐户为2800元了,造成虚读同样会使银行不知所措,到底以哪个为准。
隔离级别与读写异常(不一致)的关系如下:
容易发现,在最高隔离级别serializable下,数据不会出现读写的不一致。
问题五:数据库的锁机制?
数据库主要有这几种锁:排它锁(写锁,也称X锁)、共享锁(读锁,也称S锁)、表级锁、行级锁等等。
排它锁和共享锁其实和linux多线程同步的读写锁差不多。事务也就是相当于线程。临界区允许多个读者进入,但是同时只允许一个写者进入。
1)一个事务读取对象A,允许其他事务也读取A,但是不允许其他事务修改A。
2)一个事务修改A,不允许其他事务读取A,也不允许其他事务修改A。
表级锁:当一个事务修改表时,其他事务只能查询,不能修改,只有当修改表的事务提交或者回滚的时候,其他事务才可以获取表级锁,修改表。
行级锁:当一个事务修改该行,其他事务都不能访问改行(包括修改和读取)。
http://hi.baidu.com/franklee198/item/7335f14fcf2752eb1e19bc9a
转载于:https://my.oschina.net/yangan/blog/190086