JDBC事务机制

来源:互联网 发布:越狱软件大全 编辑:程序博客网 时间:2024/05/22 17:14
ANSI标准定义了4个隔离级别标准: •READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取还没commit的数据,这样可能会提高性能,但是dirty read可能不是我们想要的。 •READ COMMITTED:在一个事务中只允许已经commit的记录可见。如果session中select还在查询中,另一session此时insert一条记录,当前事务可以看到修改的记录,从而产生不可重复读取和幻像数据。 •REPEATABLE READ:在一个事务开始后,其他session对数据库的修改在本事务中不可见,直到本事务commit或rollback。在一个事务中重复select的结果一样,除非本事务中update数据库。   •SERIALIZABLE:最高级别的隔离,只允许事务串行执行。为了达到此目的,数据库会锁住每行已经读取的记录,其他session不能修改数据直到前一事务结束,事务commit或取消时才释放锁。 主流数据库的一般的默认是READ COMMITTED级别。 MYSQL和MS SQLServer遵守了这个定义而oracle没有。oracle只有三种事务隔离等级: •Read committed •Serializable •Read-only Read-only transactions see only those changes that were committed at the time the transaction began and do not allow INSERT, UPDATE, and DELETE statements 前两个Read committed,Serializable 和ANSI的定义是一致的,来看看最关键的第三个Read-only 。Read-only事务只会看到在这个事务开启时间点其他事务提交过的数据,并且不允许执行INSERT, UPDATE,DELETE语句,换句话说,在设置set transaction read only后,当前会话所见的数据图像,将不再受到其他会话事务的影响。 所以oracle支持的只读事务不是为了优化性能,而是为了让这个事务中所有的查询操作看到的数据是一个时间点(开启事务)上的一致数据。MYSQL,SQL_SERVER根本没有只读事务的概念,但是有REPEATABLE READ,具体看之间的差别。 有了这个基础后,再看Connection对象也定义了五个变量和ANSI标准对应: int TRANSACTION_NONE  =0;    //不受支持的事务int TRANSACTION_READ_COMMITTED =1;int TRANSACTION_READ_UNCOMMITTED = 2;int TRANSACTION_REPEATABLE_READ = 4;int TRANSACTION_SERIALIZABLE  =8;而Spring也不过是在这上面做封装。TransactionDefinition接口中定义了五个不同的事务隔离级别: int ISOLATION_DEFAULT = -1;int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

事务:由一个或多个执行、完成的语句组成,以组的形式提交或回滚。当前事务结束,另一个事务开始。

在JDBC中,事务默认是自动提交的,即每执行一条语句,就是一个事务。

事务特性:ACID特征,Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)。

  • 原子性:指整个事务是不可以分割的工作单元。只有事务中所有的操作执行成,才算整个事务成功;事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该回到执行事务前的状态。
  • 一致性:指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。例如对于银行转账事务,不管事务成功还是失败,应该保证事务结束后两个转账账户的存款总额是与转账前一致的。
  • 隔离性:指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
  • 持久性:指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。

事务各个特征的实现手段:

  • 原子性:日志
  • 一致性:日志
  • 隔离性:锁机制
  • 持久性:日志

事务隔离级别(5级):

  • 0:TRANSACTION_NONE
  • 1:TRANSACTION_READ_UNCOMMITTED
  • 2:TRANSACTION_READ_COMMITTED                防止脏读
  • 4:TRANSACTION_REPEATABLE_READ             防止不可重复读
  • 8:TRANSACTION_SERIALIZABLE                    防止 幻影读

Oracle支持2种:2和8,默认为2.

并发环境中的几种情况:

  • 脏读:一个事务在提交前可以看到另一个事务的行为,则出现脏读。一个事务读到了其它事务没有提交的数据;
  • 不可重复读:一个事务通过SQL读取数据后,有其它事务立刻作了DML操作,并且提交了,然后第一个事务通过相同的SQL语句再次读取,所得的数据和第一次读取的数据不一致的情况。
    要点:同一个事务,同一语句,在多次读取过程中,所得到的结果不一致的情况。
    如何防止:在执行SELECT语句时加上for update子句
  • 幻(影)读:基本理解同不可重复读。
    区别:
        不可重复读:指某些列的值的不同,
        幻影读:指表的总记录数量上的不同。
    如何防止:锁表,代价很高。

使用如下方法控制连接的独立性等级:

conn.setTransactionIsolation(Connection.TRANSACTION_XXX);

 

事务的开始与结束:

首先,因为默认的JDBC事务是自动提交的,故我们在获取数据库连接后,应该将连接改为非自动提交模式:

conn.setAutoCommit(false); //标志着新事务的开始

conn.commit(); //提交

conn.rollback(); //回滚

 

在JDBC 3.0新增功能中,提供对事务commit和rollback的更好支持,在事务过程中,在两个操作间可以插入一个命名的存储点作为标记,因此可以将事务回滚到那个标记,保留标记有效前的所有操作。

示例:

conn.setAutoCommit(false);

Statement stmt = conn.createStatement();

 

stmt.executeUpdate(update1);

Savepoint point1 = conn.setSavepoint("point1");

 

stmt.executeUpdate(update2);

stmt.executeUpdate(update3);

 

conn.rollback(point1);

conn.commit();