有关事务(小总结)

11年前

事务的属性:
* propagation : 事务传播行为
* isolation : 事务隔离级别
* read-only : 事务是否只读
* rollback-for : 发生哪些异常回滚 , 等同于 -Exception
* no-rollback-for : 发生哪些异常 仍然提交 ,等同于 +Exception

多个事务并发是存在的问题:
1 脏读:读未提交
 就是第一个事务查询到了第二个事务还没有提交的数据,这时候第二个事务可能会反悔,撤销动作
2 不可重复读:读已提交
 就是第一个事务在某一时间查询某条记录,第二时间又查询,原来的数据已经更新(第二个事务的更新提交后的数据),他不能判断哪个数据才是正确的,也不能保证还有没有人去改
3 幻读:读已提交
 就是第一个事务在某一时间查询某条记录,第二时间又查询,发现多了一条数据(第二个事务的insert提交后的数据)
4 丢失更新:
 两个事务操作相同的数据时,后提交的事务覆盖之前提交的事务

隔离级别:
READ_UNCOMMITED 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
READ_COMMITTED 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生
REPEATABLE_READ 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。
SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。

丢失更新问题解决: 悲观锁 和 乐观锁
    1) 悲观锁 : 假设丢失更新发生概率很大, 底层原理使用数据库内部 锁的机制
      * mysql为例,数据库内部提供 读锁(共享锁) 、写锁(排它锁 )
   * 允许一张数据表 添加多个读锁
   * 一张数据表 只能添加 一个写锁(排它锁),与其他锁 互斥 ,添加排它锁 也不能添加共享锁
   * 默认情况下,在修改记录时,会自动添加 写锁
  
   在执行查询时,也可以为数据添加 共享锁和排它锁
   select * from customer lock in share mode ;  添加共享锁
   select * from customer for update; 添加排它锁
  
   悲观锁 使用排它锁  第一个管理员修改时 select * from customer for update  第二个管理员 用同样查询需要等待
 Hibernate查询时 Session 提供 Object get(Class clazz, Serializable id, LockMode lockMode)
 mysql : LockMode UPGRADE
 oracle : LockMode UPGRADE_NOWAIT
 
 Customer customer = (Customer) session.get(Customer.class, 1 ,LockMode.UPGRADE);
  
 2) 乐观锁 : 假设丢失更新发生概率不高, 底层原理为数据添加 版本号 , 由程序来维护版本
 在Customer类中 添加 Integer version 代表 版本字段
 在Customer.hbm.xml 中添加版本字段 
  <!-- name 就是 Customer 类中 版本字段 属性名 -->
  <version name="version"></version>
 org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [cn.itcast.domain.Customer#3]

事务的传播行为(Progation)(种):
常用 : PROPAGATION_REQUIRED(默认行为) 、PROPAGATION_REQUIRES_NEW 、PROPAGATION_NESTED
 PROPAGATION_REQUIRED(默认行为) : 取款和打印凭条在同一个事务中 ,打印凭条成功,取款成功 ; 打印凭条失败 取款失败
 PROPAGATION_REQUIRES_NEW : 取款和打印凭条一定不在一个事务中 ,无论打印凭条是否成功,和取款没关系
 PROPAGATION_NESTED : 原理基于JDBC3.0 提供SavePoint ,打印凭条如果失败了, 程序是可以控制 取款操作是提交还是回滚 , 取款后,打印凭条前,savePoint , 打印凭条失败, 回滚到SavePoint