本文共 3152 字,大约阅读时间需要 10 分钟。
一、基本概念
数据库事务是指作为单个逻辑单元执行的一系列操作,要么完全的执行,要么完全的不执行。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用更加可靠。一个逻辑单元要成为事务,必须满足ACID(原子性、一致性、隔离性和永久性)。事务是数据库运行中的一个逻辑工作单位。 ① 原子性(Atomic)(Atomicity) 事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消除了系统处理操作子集的可能性。 ② 一致性(Consistent)(Consistency) 事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。某些维护一致性的责任由应用程序开发人员承担,他们必须确保应用程序已强制所有已知的完整性约束。例如,当开发用于转 帐的应用程序时,应避免在转帐过程中任意移动小数点。 ③ 隔离性(Insulation)(Isolation) 由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为隔离性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。当事务可序列化时将获得最高的隔离级别。在此级别上,从一组可并行执行的事务获得的结果与通过连续运行每个事务所获得的结果相同。由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。 ④ 持久性(Duration)(Durability) 事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。 二、数据不一致性 事务是并发控制的基本单位,保证事务ACID的特性是事务处理的重要任务,而并发操作有可能会破坏其ACID特性。由于并发操作带来的数据不一致性包括:丢失数据修改、读”脏”数据(脏读)、不可重复读、产生幽灵数据。 ① 丢失数据修改 当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。 ② 读“脏”数据(脏读) 读“脏”数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被除撤消,而此时T1把已修改过的数据又恢复原值,T2读到的数据与数据库的数据不一致,则T2读到的数据就为“脏”数据,即不正确的数据。 ③ 不可重复读 指事务T1读取数据后,事务T2执行更新操作,使T1无法读取前一次结果。 ④ 产生幽灵数据 a.按一定条件从数据库中读取了某些记录后,T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录消失 b.T1按一定条件从数据库中读取某些数据记录后,T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。三、JDBC事务机制:
当Jdbc程序向数据库获得一个Connection对象时,默认情况下这个Connection对象会自动向数据库提交在它上面发送的SQL语句。 JDBC事务设置步骤: 1)设置事务的提交方式为非自动提交:conn.setAutoCommit(false);
2)将需要添加事务的代码放入try,catch块中。
3)在try块内添加事务的提交操作,表示操作无异常,提交事务。 conn.commit();4)在catch块内添加回滚事务,表示操作出现异常,撤销事务:
conn.rollback();5)最后,设置事务提交方式为自动提交:
conn.setAutoCommit(true);dbc = new DataBaseConnection();Connection con = dbc.getConnection();try { con.setAutoCommit(false);// 更改JDBC事务的默认提交方式 dbc.executeUpdate(sql1); dbc.executeUpdate(SQL2); dbc.executeUpdate(SQL3); con.commit();//提交JDBC事务 }catch (Exception exc) { con.rollBack();//回滚JDBC事务 exc.printStackTrace(); }finally{ con.setAutoCommit(true);// 恢复JDBC事务的默认提交方式 dbc.close(); }
四、JDBC事务级别
JDBC API支持事务对数据库的加锁,并且提供了5种操作支持: ① static int TRANSACTION_NONE = 0; 说明不支持事务 ② static int TRANSACTION_READ_UNCOMMITTED = 1; 明在提交前一个事务可以看到另一个事务的变化。这样脏读、不可重复的读和虚读都是允许的。 ③ static int TRANSACTION_READ_COMMITTED = 2; 说明读取未提交的数据是不允许的。这个级别仍然允许不可重复的读和虚读产生。 ④ static int TRANSACTION_REPEATABLE_READ = 4; 说明事务保证能够再次读取相同的数据而不会失败,但虚读仍然会出现。 ⑤ static int TRANSACTION_SERIALIZABLE = 8; TRANSACTION_SERIALIZABLE 是最高的事务级别,它防止脏读、不可重复的读和虚读。 事务保护的级别越高,性能损失就越大。 JDBC根据数据库提供的默认值来设置事务支持及其加锁,当然,也可以手工设置:setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
需要注意的是,在进行手动设置时,数据库及其驱动程序必须得支持相应的事务操作操作才行。 可以查看数据库的当前设置: getTransactionIsolation () 五、总结 上述设置随着值的增加,其事务的独立性增加,更能有效地防止事务操作之间的冲突,同时也增加了加锁的开销,降低了用户之间访问数据库的并发性,程序的运行效率也会随之降低。因此得平衡程序运行效率和数据一致性之间的冲突。一般来说,对于只涉及到数据库的查询操作时,可以采用 TRANSACTION_READ_UNCOMMITTED方式;对于数据查询远多于更新的操作,可以采用 TRANSACTION_READ_COMMITTED方式;对于更新操作较多的,可以采用TRANSACTION_REPEATABLE_READ;在 数据一致性要求更高的场合再考虑最后一项,由于涉及到表加锁,因此会对程序运行效率产生较大的影响。另外,在Oracle中数据库驱动对事务处理的默认值TRANSACTION_NONE,即不支持事务操作,所以需要在程序中手动进行设置。 总之,JDBC提供的对数据库事务操作的支持是比较完整的,通过事务操作可 以提高程序的运行效率,保持数据的一致性。转载地址:http://owmgb.baihongyu.com/