数据库事务(Database Transaction)是指作为单个逻辑工作单元执行的一系列操作,要么完整地执行,要么完全地不执行。
事务由作为包执行的单个命令或一组命令组成。 通过事务可以将多个操合并为单个工作单元。 如果在事务中的某一点发生故障,则所有更新都可以回滚到其事务前状态。
事务必须符合 ACID 属性(原子性、一致性、隔离和持久性)才能保证数据的一致性。
利用事务维护数据库的完整性
尽管我们可以使用子查询(Sub-Queries)、连接(JOIN)和联合(UNION)来创建各种各样的查询,但不是所有的数据库操作都可以只用一条或少数几条SQL语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下,当这个语句块中的某一条语句运行出错的时候,整个语句块的操作就会变得不确定起来。设想一下,要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的操作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事物以BEGIN 关键字开始,COMMIT关键字结束。在这之间的一条SQL操作失败,那么,ROLLBACK命令就可以把数据库恢复到BEGIN开始之前的状态。
BEGIN;
INSERT INTO salesinfo SET CustomerID=14;
UPDATE inventory SET Quantity=11
WHERE item='book';
COMMIT;
事务的另一个重要作用是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其它的用户所干扰。
锁定表
尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的独占性,有时会影响数据库的性能,尤其是在很大的应用系统中。由于在事务执行的过程中,数据库将会被锁定,因此其它的用户请求只能暂时等待直到该事务结束。如果一个数据库系统只有少数几个用户来使用,事务造成的影响不会成为一个太大的问题;但假设有成千上万的用户同时访问一个数据库系统,例如访问一个电子商务网站,就会产生比较严重的响应延迟。
其实,有些情况下我们可以通过锁定表的方法来获得更好的性能。下面的例子就用锁定表的方法来完成前面一个例子中事务的功能。
LOCK TABLE inventory WRITE
SELECT Quantity FROM inventory
WHEREItem='book';
...
UPDATE inventory SET Quantity=11
WHEREItem='book';
UNLOCK TABLES
这里,我们用一个 SELECT 语句取出初始数据,通过一些计算,用 UPDATE 语句将新值更新到表中。包含有 WRITE 关键字的 LOCK TABLE 语句可以保证在 UNLOCK TABLES 命令被执行之前,不会有其它的访问来对 inventory 进行插入、更新或者删除的操作。
声明事务的边界:
(1)mysql声明事务
每个数据库都有个全局变量@@autocommit,表示当前的事务模式:0:手工提交模式,1:默认为自动提交模式.
Mysql查看事务模式
查看当前事务模式:select @@autocommit
设置当前事务模式: set autocommit = 0;
提交事务
l 自动提交模式下提交事务
每个SQL语句都是一个独立的事务。自动提交事务
l 手动提交模式
事务的开始边界:begin
提交事务:commit
撤销事务:rollback
(2)jdbc api声明事务
Connection提供了用于控制事务的方法
l setAutoCommit(boolean autoCommit):设置是否自动提交事务
l Commit:提交事务
l Rollback:撤销事务
(3)Hibernate声明事务
声明事务开始的边界:Transaction tx = session.beginTransaction();
提交事务:tx.commit()
撤销事务:tx.rollback()
多个事务的并发问题
假设,存在两个事务(T1、T2)并发执行
(1)脏读:一个事务读到了另一个事务未提交的更新数据
T1读取了T2修改但还未提交的数据,由于某种错误T2回滚,则T1读取就是无效数据。
(2)不可重复读:一个事务读到另一事务提交的更新数据
T1读取一个字段,之后T2更新了该字段,T1再次读取该字段发生了变化。
一个事务对同一行数据重复读取两次,但却得到不同的结果,同一查询在事务中进行多次,由于其他事务做了修改或删除,每次返回不同的结果集,此时发生不可重复读。
(3)虚读:一个事务读到另一个事务已提交的新插入的数据
T1从一个表中读取数据,然后T2在该表中插入新的行,T1再次读取该表时发现结果多几行
(3)丢失更新:这是不可重复读中的特例,一个事务覆盖另一事务已提交的更新数据。
数据库事务的特性:原子性、一致性、隔离性、持久性
原子性:事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据修改操作要么全部执行,要么完全不执行,这种特性称为原子性。(简单地说就是,几个对于数据库的操作要么全执行,要么全不执行,即同时成功起作用或同时失败没影响)
一致性:事务一致性值得是在一个事务执行之前和执行之后数据库都必须处于一致性状态(中途是否一致不用管),这种特性称为一致性。(如果数据库的状态满足所有的完整性约束,就说该数据库是一致的。一致性处理数据库中对所有语义的保护。如:客户K1要向客户K2转账,K1账户减少的金额就是K2账户增加的金额,在转账之前K1和K2账户的金额之和与转账之后K1和K2账户的金额之和是一样的,在转账期间可能不满足这种一致性,但事务前后是数据库数据是一致的)
隔离性:隔离性指的是并发的事务是相互隔离的。(一个事务内部的操作及正在操作的数据必须封装起来,不被其它企图进行修改的事务看到)
持久性:持久性指当系统或介质发生故障时,确保已提交的更新不能丢失。(一个事务提交,DBMS保证它对数据库中数据的改变应该是永久性的,可以经受任何系统故障,持久性通过数据库备份和恢复来保证)