jdbc事务和事务的隔离级别
在jdbc的使用中以最简单的jdbc的使用为例,说明了jdbc的具体用法。然而在通常项目中,需要考虑更多内容,例如事务。
事务,在单个数据处理单元中,存在若干个数据处理,要么整体成功,要么整体失败。事务需要满足ACID属性(原子性、一致性、隔离性和持久性)。
- 原子性:所谓原子性是指本次数据处理要么都提交、要么都不提交,即不能先提交一部分,然后处理其他的程序,然后接着提交未完成提交的剩余部分。概念类似于编程语言的原子操作。
- 一致性:所谓一致性是指数据库数据由一个一致的状态在提交事务后变为另外一个一致的状态。例如,用户确认到货操作:确认前,订单状态为待签收、客户积分为原始积分,此状态为一致的状态;在客户确认到后后,订单状态为已完成、客户积分增加本次消费的积分,这两个状态为一致状态。不能出现,订单状态为待签收,客户积分增加或者订单状态为已完成,客户积分未增加的状态,这两种均为不一致的情况。一致性与原子性息息相关。
- 隔离性:所谓隔离性是指事物与事务之间的隔离,即在事务提交完成前,其他事务与未完成事务的数据中间状态访问权限,具体可通过设置隔离级别来控制。
- 持久性:所谓持久性是指本次事务提交完成或者回滚完成均为持久的修改,除非其他事务进行操作否则数据库数据不能发生改变。
本文重点描述事物隔离性及使用方法。
要详细说明数据库隔离级别,需要先对数据库并发事务可能出现的几种状态进行说明:
- 读脏:一个事务读取另外一个事务尚未提交的数据。如下图,线程thread1在事务中在time1时刻向库表中新增一条数据‘test’并在time3时刻回滚数据;线程thread2在time2时刻读取,若thread2读取到‘test’,则为读脏。
- 不可重新读:其他事务的操作导致某个事务两次读取数据不一致。如下图,线程thread1在事务中time1时刻将数据库中‘test’更新为‘00’,并在time3时刻提交;thread2在一个事务中分别在time2和time4两个时刻读取这条记录,若两次读取结果不同则为不可重读。(注意:1.不可重读针对已经提交的数据。2.两次或多次读取同一条数据。)
- 幻读:其他事务的数据操作导致某个事务两次读取数据数量不一致。如下图,线程thread1在事务中time1时刻向数据库中新增‘00’,并在time3时刻提交;thread2在一个事务中分别在time2和time4两个时刻扫描库表,若两次读取结果不同则为幻读。(注意:1.幻读针对已经提交的数据。2.两次或多次读取不同行数据,数量上新增或减少。)
针对上诉3中事务并发情况,jdbc定义了5中事务隔离级别:
- TRANSACTION_NONE 无事务
- TRANSACTION_READ_UNCOMMITTED
允许读脏,不可重读,幻读。
- TRANSACTION_READ_COMMITTED
直译为仅允许读取已提交的数据,即不能读脏,但是可能发生不可重读和幻读。
- TRANSACTION_REPEATABLE_READ
不可读脏,保证同一事务重复读取相同数据,但是可能发生幻读。
- TRANSACTION_SERIALIZABLE
直译为串行事务,保证不读脏,可重复读,不可幻读,事务隔离级别最高。
**> 注意:
- 隔离级别对当前事务有效,例如若当前事务设置为TRANSACTION_READ_UNCOMMITTED,则允许当前事务对其他事务未提交的数据进行读脏,而非其他事务可对当前事务未提交的数据读脏。
- 部分数据库不支持TRANSACTION_NONE,例如mysql。
- 在TRANSACTION_SERIALIZABLE 隔离级别下,为先执行DML更新,再执行查询,此处为实验的结论。
- 若未显示设置隔离级别,jdbc将采用数据库默认隔离级别。文中实验数据库的默认隔离级别为:**
-
-
MySQL中默认的事物隔离级别为TRANSACTION_REPEATABLE_READ 不可脏读,
-
Oracle中事务隔离级别默认TRANSACTION_READ_COMMITTED