Hibernate学习笔记_事务

 事务并发处理(面试的意义更大)                       

a)   事务:ACID

i.   Atomic(原子性) Consistency(一致性) Isolation(隔离性) Durability(独立性)

b)   事务并发时可能出现的问题:

第一类丢失更新(Lost Update)


时间


取款事务A


存款事务B


T1


开始事务


 


T2


 


开始事务


T3


查询账户余额为1000元


 


T4


 


查询账户余额为1000元


T5


 


汇入100元把余额改为1100元


T6


 


提交事务


T7


取出100元把余额改为900 元


 


T8


撤销事务


 


T9


余额恢复为1000元(丢失更新)


 

dirty read脏读(读到了另一个事务在处理中还未提交的数据)


时间


取款事务A


存款事务B


T1


开始事务


 


T2


 


开始事务


T3


 


查询账户余额为1000元


T4


 


汇入100元把余额改为1100元


T5


查询账户余额为1100元(读取脏数据)


 


T6


 


回滚


T7


取款1100


 


T8


提交事务失败


 

non-repeatable read 不可重复读


时间


取款事务A


存款事务B


T1


开始事务


 


T2


 


开始事务


T3


查询账户余额为1000元


 


T5


 


汇入100元把余额改为1100元


T5


 


提交事务


T6


查询帐户余额为1100元


 


T8


提交事务


 

second lost update problem 第二类丢失更新(不可重复读的特殊情况)


时间


取款事务A


存款事务B


T1


 


开始事务


T2


开始事务


 


T3


 


查询账户余额为1000元


T4


查询账户余额为1000元


 


T5


 


取出100元把余额改为900元


T6


 


提交事务


T7


汇入100元


 


T8


提交事务


 


T9


把余额改为1100元(丢失更新)


 

phantom read 幻读


时间


查询学生事务A


插入新学生事务B


T1


开始事务


 


T2


 


开始事务


T3


查询学生为10人


 


T4


 


插入1个学生


T5


查询学生为11人


 


T6


 


提交事务


T7


提交事务


 

c)   数据库的事务隔离机制

i.   查看 java.sql.Connection 文档

ii.   1:read-uncommitted  2:read-committed  4:repeatable read  8:serializable(数字代表对应值)

为什么取值要使用 1 2 4 8 而不是 1 2 3 4

1=0000  2=0010 4=0100 8=1000(位移计算效率高)

  1. 只要数据库支持事务,就不可能出现第一类丢失更新
  2. read-uncommitted(允许读取未提交的数据) 会出现dirty read, phantom-read,non-repeatable read 问题
  3. read-commited(读取已提交的数据 项目中一般都使用这个)不会出现dirty read,因为只有另一个事务提交才会读出来结果,

    但仍然会出现 non-repeatable read 和 phantom-read

    使用read-commited机制可用悲观锁 乐观锁来解决non-repeatable read 和 phantom-read问题

4.repeatable read(事务执行中其他事务无法执行修改或插入操作     较安全)

5.serializable解决一切问题(顺序执行事务 不并发,实际中很少用)

d)   设定hibernate的事务隔离级别(使用hibernate.connection.isolation配置 取值1、2、4、8)

i.   hibernate.connection.isolation = 2(如果不设 默认依赖数据库本身的级别)

ii.   用悲观锁解决repeatable read的问题(依赖于数据库的锁)

@Test
    public void testPessimisticLock() {
        Session session = sf.openSession();
        session.beginTransaction();

        Account a = (Account)session.load(Account.class, 1, LockMode.UPGRADE);
        int balance = a.getBalance();
        //do some caculation
        balance = balance - 10;
        a.setBalance(balance);
        session.getTransaction().commit();
        session.close();
    }
  1. select ... for update

2.使用另一种load方法--load(xx.class , i , LockMode.Upgrade)

a)  LockMode.None无锁的机制,Transaction结束时,切换到此模式

b)  LockMode.read在査询的时候hibernate会自动获取锁

c)  LockMode.write insert  update hibernate 会自动获取锁

d)  以上3种锁的模式,是hibernate内部使用的(不需要设)

e)  LockMode.UPGRADE_NOWAIT是 ORACLE 支持的锁的方式

e)   Hibernate(JPA)乐观锁定(ReadCommitted)

实体类中增加version属性(数据库也会对应生成该字段,初始值为0),并在其get方法前加@Version注解,

则在操作过程中没更新一次该行数据则version值加1,即可在事务提交前判断该数据是否被其他事务修改过.

@Entity
public class Account {
    private int id;
    private int balance;
    private int version;
    @Version
    public int getVersion() {
        return version;
    }
    public void setVersion(int version) {
        this.version = version;
    }
....................
}
@Test
    public void testOptimisticLock() {
        Session session = sf.openSession();

        Session session2 = sf.openSession();

        session.beginTransaction();
        Account a1 = (Account) session.load(Account.class, 1);

        session2.beginTransaction();
        Account a2 = (Account) session2.load(Account.class, 1);

        a1.setBalance(900);
        a2.setBalance(1100);

        session.getTransaction().commit();
        System.out.println(a1.getVersion());

        session2.getTransaction().commit();
        System.out.println(a2.getVersion());

        session.close();
        session2.close();
    }

时间


转账事务A


取款事务B


T1


 


开始事务


T2


开始事务


 


T3


查询学生为10人


查询账户余额为1000 version=0


T4


查询账户余额为1000 version=0


T5


取出100 把余额改为900 version=1


T6


提交事务


T7


汇入100元


 


T8


提交事务 ? version>0

throw Exception


 


T9


把余额改为1100元(丢失更新)

时间: 2024-10-23 10:09:09

Hibernate学习笔记_事务的相关文章

Hibernate学习笔记_查询

HQL vs EJBQL 1         NativeSQL >HQL.> EJBQL(JPQL 1.0) > QBC(Query By Criteria) > QBE(Query By Example)" 2         总结:QL应该和导航关系结合,共同为査询提供服务. @Test public void testHQL_01() { Session session = sf.openSession(); session.beginTransaction();

Hibernate学习笔记_缓存

一级缓存和二级缓存和査询缓存(面试题)                 a)    什么是缓存 b)    什么是一级缓存,session级别的缓存 c)    什么是二级缓存,SessionFactory级别的缓存,可以跨越session存在 i.   经常被访间 ii.   改动不大不会经常改动 iii.   数重有限 d)    打开二级缓存 i.   hibernate.cfg.xml 设定: <property name= "cache.use_second_level_cach

Hibernate学习笔记_联合主键

复合主键(联合主键):多个字段构成唯一性. 一,xml方式 1. 将联合主键的属性提取出来,重新编写一个StudentPK类(原Student类中的id,name要删除 并新加入属性“StudentPK”) //StudentPK .javapackage com.bjsxt.hibernate; public class StudentPK implements java.io.Serializable{ private int id; private String name; public

hibernate学习笔记_基础配置

一.hibernate.cfg.xml: hbni2ddl.auto 二.搭建日志环境并配置显示DDL语句 我们使用slf接口,然后使用log4j的实现. 1.  首先引入log4j的jar包(log4j-1.2.14.jar), 2.  然后再引入slf4j实现LOG4J和适配器jar包(slf4j-log4j12-1.5.8.jar) 3.  最后创建log4j的配置文件(log4j.properties),并加以修改,只要保留 log4j.logger.org.hibernate.tool

Hibernate学习笔记_关系映射

    一对一关联     一,     一对一单向外键关联 a)    Annotation: 在被约束表字段的get方法上加@0ne20ne @JoinColumn //Husband .java @Entity public class Husband { private int id; private String name; private Wife wife; @Id @GeneratedValue public int getId() { return id; } public S

Hibernate学习笔记_性能优化

注意session.clear()的运用,尤其在不断分页循环的时候 a)    在一个大集合中进行遍历,遍历msg,取出其中的含有敏感字样的对象 b)    另外一种形式的内存泄露  (  //面试题:Java有内存泄漏吗?语法级别没有 但是可由java引起,例如:连接池不关闭,或io读取后不关闭) 1+N问题 (典型的面试题)                                              a)    @ManyToOne(fetch=FetchType.LAZY)

Hibernate学习笔记_关系映射_其他

集合映射(不太重要) 1         Set 2        List (与Set差不多 多个@OrderBy) a) @OrderBy     排序 private List<User> users = new ArrayList<User>(); @OneToMany(mappedBy="group", cascade={CascadeType.ALL} ) @OrderBy("name ASC") public List<U

Hibernate学习笔记_关系映射_树状结构练习

1         树状结构的设计(至关重要) a) 在同—个类中使用One2Many和Many20ne @Entity public class Org { private int id; private String name; private Set<Org> children=new HashSet<Org>(); private Org parent; @Id @GeneratedValue public int getId() { return id; } public

hibernate学习笔记之三(一级缓存的使用和管理)

(hibernate学习笔记系列来自于 "疯狂Java" Hibernate视频学习) 一级缓存 一级缓存生命周期很短,与session生命周期一致,所以一级缓存也叫session级缓存或事务级缓存.位于缓存中的对象处于持久化状态,它与表中的相关记录对应,session能够在某些时间点,按照缓存中持久化对象的属性来同步数据库中表的记录,这一过程称为清理缓存. 一级缓存实现原理. session缓存是由它的实现类sessionImpl中定义的一些集合属性构成的,原理是保证有一个引用在关联