Hibernate实战 读书笔记

第9章 使用对象

第10章 事务与并发

数组库级并发

  1. 事务隔离性问题

    • 丢失更新 (lost update)

      两个事务更新没有加锁的的同一数据, 第二个事务异常终止,就会回滚事务,造成两次变化都丢失.

    • 脏读取 (dirty read)

      事务A读取了事务B没有提交的事务进行的改变.事务B进行的改变随后可能回滚.

    • 不可重复读取 (unrepeatable read)

      如果一个事务读取一个行两次,并且每次读取到不同的結果,就会发生不可重复读取.如另一个事务在两次读取之间写到这一行,并已在两次读取之间提交.

    • 二次丢失更新问题 (second lost update problem)

      两个并发事务都读取一个行: 一个写到行并提交,然后另一停止了写到行提交.由第一个事务所做的改变丢失了.

    • 幻读 (phantom read)

      一个事务执行一个查询两次,并且第二个結果集包括了第一个結果集中不可见的行,或者包括了已经删除的行. 这种情况是由另一个事务在两次查询执行之间插入或者删除行造成的. (个人理解, 幻读与不可重复读取的区别应该是幻读强调的是結果集记录数的改变)

  2. 事务隔离性级别

    • 读取未提交 (read uncommitted)

      允许脏读但是不允许丢失更新. 如果一个未提交事务已经写到一行,另一个事务就不可能再写到这一行.但是任何事务都可以读取任何行.

    • 读取提交 (read committed)

      允许不可重复读取但不允许脏读取. 读取事务不会阻塞其他事务访问.但是未提交的写事务阻塞所有其他的事务访问该行.

    • 可重复读取 (repeatable read)

      不允许不可重复读取, 不允许脏读取.(幻读可能发生) 读取事务阻塞写事务(但是不阻塞其他的读事务),并且写事务阻塞所有其他的事务.

    • 可序列化 (serializable)

      最严格的事务隔离性.这个隔离性模拟连续的事务执行,好像事务是连续地一个接一个执行,而不是并发地执行.

    隔离性级别的增加带来了更高成本以及严重的性能退化和可伸缩性.

  3. 设置Hibernate事务隔离级别

    通过 hibernate.connection.isolation 来设置 hibernate 的隔离性级别. hibernate.connection.isolation的值和意义是:

    • 1 – 读取未提交
    • 2 – 读取提交
    • 3 – 可重复读取
    • 4 – 可序列化

乐观并发控制

乐观并发控制始终假设一切都会很好.多用户的应用程序通常默认为使用读取提交隔离性级别的乐观并发控制和数据库连接. 只有适当的时候(例如, 当需要可重复读取的时候)才获得额外的隔离性保证. 这种方法保证了最佳的性能和伸缩性.

Hibernate乐观锁要解决的问题是, 两个更新哪一个要生效.

有3种选择:

  • 最晚提交生效 (last commit wins)
  • 最早提交生效 (first commit wins)
  • 合并冲突更新 (merge conflicting updates)

如果没有启用乐观并发控制, 则默认为最晩提交生效, 用户会因为自己的工作丢失而非常沮丧, hibernate 乐观锁控制采用最早提交生效.

Hibernate通过在类中添加一个version字段, 每次对实体执行DML语句时,都会去更新version(where子句里将version作为条件之一) , 当另一段代码想更新这个实体时, 它的DML会报错, 因为在数据库中已经找不到version对应的那条记录了.

Hibernate的自动版本控制, 在两个并发事务试图在同一块代码中提交修改时,防止了丢失更新,为了处理不可重复读取,你需要额外的隔离性保证.

(其实丢失更新不只是之前提到的两个写操作时一个失败将两次更新都回滚, 它的另外一种情况就是后发生的更新覆盖了之前的更新,导致之前的 更新丢失, Hibernate版本控制是为来保证先更新的結果被保留下来)

如果想提交可重复读取隔离级别,需要使用Hibernate悲观锁在多次读取之间将指定实体锁住.

Table Of Contents

Previous topic

Java Programming

Next topic

Web Security

This Page