所谓隔离性实际上就意味着数据库如何处理并发操作的问题,当两个或者多个操作(或事务)操作同一个数据时,可能引起访问的冲突和数据库的不一致。例如,一个线程需要读取数据库中的某条记录,而另一条线程却要对该条记录进行更新,这就需要通过隔离级的设置来告诉数据库如何处理各种冲突情况。
根据JDBC规范的定义,事务的隔离设置一共分为5种级别,这5种级别的详细规定则依赖于具体使用的数据库。因此在实际应用中还需要查阅底层数据库和JDBC驱动程序的相关文档。下面是对这5种隔离级别(Connection 接口中定义了这5 种隔离级别常量)的简单介绍。
TRANSACTION_NONE:对事务和数据不进行任何隔离限制。
TRANSACTION_UNCOMMITTED(读未提交):这种隔离级别允许事务读取另一个事务的未提交数据。举例来说,A线程将某帐户的余额减少了1000元,即使在事务A未提交之前,当事务B试图读取该账户余额时,它也将读到减少后的账户余额。在这种隔离级别下,尽管事务A没有提交,但事务B读到的总是最新的数据。但这种隔离级别有一个很严重的问题:读取脏数据!对于前面介绍的情形,当事务B读取到未提交的帐户余额之后,如果事务A又回滚了(没有提交),那意味着B读的数据是不正确的!这就叫读取了脏数据 (有的地方也简称脏读)。
TRANSACTION_READ_COMMITTED(读已提交):这种隔离级别保证所有读到的数据都是已提交的数据,这种隔离级别可以防止第二种情况的出现 ,但它不允许重复读。举例来说,当事务A开始读到某条记录的帐户余额为2000元时,在事务A未提交之前,事务B把这条记录的帐户余额改为1000元,并提交了事务B,当事务A再次读取此务记录的帐户余额时将读到1000元,这就是不可重复读。因为对于同一条数据记录,事务A读取了两次,但两次读到的结果并不相同,对于Oracle数据库而言,是默认的隔离级别,在应用中通常采用这种隔离设置。
TRANSACTION_REPEATABLE_READ(可重复读):这种隔离级别可以防止第二、第三种情况的出现,它是一种可重复的事务隔离。但当其他关联表中的数据行被插入或删除时,读事务依然可能出现 一种边界效应,从而造成某种程度的错觉。假设现在数据库中有两个表:表一记录了当前全部学生的详细记录(假设每条记录代表一个学生);表二则记录了包括学生总人数、男生人数、女生人数等。事务A读取表一记录,并计算出学生总人数、男生人数、女生人数等统计信息,接下来事务B向表一中插入记录并修改表二的统计记录,如果此时恰好事务A去读取表二中的统计信息,并用读到的统计信息与之前通过表一计算出来统计信息进行对比,将会发现两组统计信息并不相等(新读到的统计数据更大)。
TRANSACTION_SERIALIZABLE(序列化):这种隔离设置可以防止第二、第三、第四种情形的出现。代表真正可串行化的事务,提供了最高级别的保护 ,但这种事务方式的性能也是最低级的。
设置JDBC访问的隔离级别,可调用Connection接口中定义的setTransactionIsolation()方法,该方法可以接受一个int 类型的常量作为事务的隔离级别,Connection接口中定义的隔离级别常量就是前面我们介绍的5个常量。例如:conn.setTransationIsolation(Connection.TRANSACTION_REPEATABLE_READ);
注意:由于事务隔离级别需要底层数据库的支持,但并不是每个数据库都支持所有的隔离级别,不同的数据库也可能采用不同的锁定算法,因此当通过JDBC设置隔离级别时还需要查阅底层数据库的相关资料。