Hibernate学习总结——SessionFactory对象和其他对象总结

SessionFactory对象

SessionFactroy接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。可以通过Configuration实例构建SessionFactory对象。

  1. SessionFactory是生成Session的工厂;当客户端发送一个请求线程时,SessionFactory生成一个Session 对象来处理客户请求。
  2. SessionFactory在应用初始化时被创建,是一个重量级的类,它在多个应用线程间进行被共享,通常情况下,整个应用只有唯一的一个会话工厂,然而,如果你使用Hibernate访问多个数据库,你需要对每一个数据库使用一个会话工厂
  3. SessionFactory是线程安全的,可以被多个线程调用。
Configuration cfg=new Configuration().configure(); 
SessionFactory sf=cfg.buildSessionFactory(); 

Session 对象

Session对象是Hibernate技术的核心,持久化对象的生命周期、事务的管理和持久化对象的查询、更新和删除都是通过Session对象来完成的。

  1. Session 是应用程序与数据库之间交互操作的一个单线程对象,是 Hibernate 运作的中心,所有持久化对象必须在 session 的管理下才可以进行持久化操作。此对象的生命周期很短
  2. Hibernate在操作数据库之前必须先取得Session对象,相当于JDBC在操作数据库之前必须先取得Connection对象一样
  3. Session对象通过SessionFactory对象的getCurrentSession()或者openSession()方法获取
    Configuration cfg= new Configuration().configure();
    SessionFactory sf= cfg.buildSessionFactory();
    Session session=sf.openSession();
  4. Session 类方法的用途可分为以下5类:

    – 取得持久化对象的方法: get(),load()
    – 持久化对象都得保存,更新和删除:save(),update(),saveOrUpdate(),delete()
    – 开启事务: beginTransaction().
    – 管理 Session 的方法:isOpen(),flush(),clear(),evict(),close()

Transaction对象

Transaction将应用代码从底层的事务实现中抽象出来——可能是一个JDBC事务或一个JTA事务,这有助于保持Hibernate应用在不同类型的执行环境或容器中的可移植性。

  1. 使用Hibernate进行操作时(增、删、改)必须显示的调用Transaction(默认autoCommit=false)
  2. Transaction的运行与Session接口相关,可调用Session的beginTransaction()方法生成一个Transanction实例。
    Transaction tx = session.beginTransaction();
  3. 常用方法:
    – commit():提交相关联的session实例
    – rollback():撤销事务操作
    – wasCommitted():检查事务是否提交

Hibernate持久化对象

  1. 持久化类的要求
    1. 必须提供一个无参数的构造函数可以不采用public访问控制符,但为了方便Hibernate在运行时生成代理,构造函数的访问控制符至少是包可见的(即大于或等于默认的访问控制符)
    2. 提供一个标识属性:通常映射数据库表的主键字段;可以是任何名字、任何类型(基本类型、包装类、String或Date);如果使用联合主键,甚至可以用一个用户自定义的类,该类包括这些类型的属性
    3. 为持久化类的每个成员变量提供setter和getter方法;注意:变量名首字符小写
    4. 使用非final的类,在运行时生成代理是Hibernate的一个重要功能。如果持久化类没有实现任何接口,使用Javassist生成代理,该代理对象是持久化类的子类的对象;如果使用了final类,就无法生成Javassist代理,因此需要让Hibernate持久化类实现一个所有方法都声明为public的接口,此时将使用JDK代理,同时避免在非final类中声明public final方法。如果必须要有一个final方法,必须设置lazy=“false”明确的禁用代理

相关名词

  1. OID(Object Identifier, OID):来建立内存中的对象和数据库表中记录的对应关系,对象的OID和数据库表的主键(通常为代理主键,即不具备业务含义的字段,该字段一般取名为ID)对应。它是hibernate用于区分两个对象是否是同一个对象的标识。为了保证持久化对象的OID的唯一性和不可变性,通常由Hibernate或底层数据库来给OID赋值。因此,可以把OID的setId()方法设为private类型,以禁止Java应用程序随便修改OID;而把getId()方法设为public类型,这使得Java应用程序可以读取持久化对象的OID
  2. 自然主键:把具有业务含义的字段作为主键,称之为自然主键。
  3. 代理主键:把不具备业务含义的字段作为主键,称之为代理主键。该字段一般取名为“ID”,通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间。
  4. hibernate中的一级缓存:是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。
    在运行时,Hibernate根据OID来维持Java对象和数据库中的对应关系。如下所示:
    Transaction tx = session.beginTransaction();
    User user1 = (User)session.load(User.class,new Long(1));
    User user2 = (User)session.load(User.class,new Long(1));
    User user3 = (User)session.load(User.class,new Long(3));
    应用程序在执行上述代码时,第一次OID为1的对象,从数据库中查找ID为1的记录,然后创建想要的User实例,并把它保存到session的缓存中,最后将该实例的引用赋值给变量user1,第二次加载OID为1的对象时,直接把session缓存中的OID为1的实例的引用赋值给user2,因此user1=user2的结果为true
  5. 快照机制:Hibernate 向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。

持久化对象的状态

临时态(自由态)

  1. 由new命令开辟内存空间时刚生成的Java对象就处于临时态。
    例如:UserInfoPO ui=new UserInfoPO();
  2. 临时对象在内存中是孤立存在,它是携带信息的载体,不和数据库的数据有任何关联关系,在Hibernate中,可通过session的save()或saveOrUpdate()方法将临时对象与数据库相关联,并将数据对应的插入数据库中,此时该临时对象转变成持久化对象。
  3. 没有OID,没有和Session建立关系(没有存入Session的一级缓存),数据表中行数据与对象没有关系

持久态

  1. 处于该状态的对象在数据库中具有对应的记录,并拥有一个持久化标识。如果是用Hibernate的delete()方法,对应的持久对象就变成临时对象,因数据库中的对应数据已被删除,该对象不再与数据库的记录关联。
  2. 当一个session执行close()或clear()、evict()之后,持久对象变成脱管对象,此时持久对象会变成脱管对象,此时该对象虽然具有数据库识别值,但它已不在Hibernate持久层的管理之下。
  3. 持久对象具有如下特点:
    – 和session实例关联。
    – 在数据库中有与之关联的记录。
    有OID,和Session建立关系(存入Session的一级缓存),数据表中行数据与对象建立关系

脱管态(游离态)

  1. 当与某持久对象关联的session被关闭后,该持久对象转变为脱管对象。当脱管对象被重新关联到session上时,并再次转变成持久对象。
  2. 脱管对象拥有数据库的识别值,可通过update()、saveOrUpdate()等方法,转变成持久对象。
  3. 脱管对象具有如下特点:
    – 本质上与临时对象相同,在没有任何变量引用它时,JVM会在适当的时候将它回收。
    – 比临时对象多了一个数据库记录标识值。
    – 有OID,和Session没有关系(从Session的一级缓存中移除),数据表中行数据与对象没有关系

Session的基本操作

1. save()方法

– Session的save()方法使一个临时对象转变为持久化对象
Session的save() 方法完成以下操作:

  1. 把News对象加入到 Session 缓存中, 使它进入持久化状态
  2. 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 在使用代理主键的情况下, setId()方法为对象设置OID是无效的.执行save()方法之前,修改对象id的操作是无效的。
  3. 计划执行一条insert语句:在flush缓存的时候
    Hibernate通过持久化对象的OID来维持它和数据库相关记录的对应关系。当News对象处于持久化状态时,不允许程序随意修改它的ID
2. persist()方法 【Save_Persis】

save()和 persist()方法还有一个区别:

  1. 返回类型不同,save返回Serializable对象,而persist返回void
  2. ID赋值时机不同,二者同样用于将transient实例持久化,但persist不保证ID值立即赋给持久化实例,可能会在flush的时候给ID赋值。
  3. transaction外的行为不同,save方法会导致insert语句的立即执行;persist如果在transaction之外调用,不会导致insert语句的立即执行,而是在flush时执行insert语句。persist如果在transaction之内调用,会导致insert语句的立即执行。
  4. 使用场景,由于上述第三点区别,persist方法适用于被扩展的Session上下文的长期运行的会话中;而save则不适用。

如果标识属性时自动生成,那么Hibernate将会在执行save方法时自动生成标识属性,并将该标识属性值分配给对象;如果标识属性是assigned(指派)属性或复合主键那么标识属性值应当在调用save之前手动赋给对象

3. get()和load()方法 【Load_Get】

都可以根据给定的 OID 从数据库中加载一个持久化对象
区别:
使用get()来根据ID进行单条查询,当get()方法被调用的时候就会立即发出SQL语句;当调用load()方法的时候会返回一个目标对象的代理对象。在使用对象之前提前关闭了session会发生懒加载异常。get方法不存在这个问题。
当数据库中不存在与 OID 对应的记录时,Session没有关闭且同时需要使用对象时, load() 方法抛出 ObjectNotFoundException 异常, 而 get() 方法返回 null

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

懒加载异常
在这里插入图片描述
在hibernate设置延迟加载后,hibernate返回给我们的对象(要延迟加载的对象)是一个代理对象并不是真实的对象,该对象没有真实对象的数据,只有真正需要用到对象数据(调用getter等方法时)时,才会触发hibernate去数据库查对应数据,而且查回来的数据不会存储在代理对象中,所以这些数据是无法在调试窗口查看到的。

4. update() 方法 【update】
  1. Session 的 update() 方法使一个游离对象转变为持久化对象, 并且计划执行一条 update 语句.
  2. 若希望 Session 仅当修改了 News 对象的属性时, 才执行 update() 语句, 可以把映射文件中 元素的 select-before-update 设为 true. 该属性的默认值为 false
  3. 抛出异常的两种情况:
    a) 当 update() 方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常
    b) 当 update() 方法关联一个游离对象时, 如果在数据库中不存在相应的记录, 也会抛出异常.
5. saveOrUpdate方法
  1. 有save()和update()方法的功能,对于传入的对象,首先会执行一遍查询语句判断该对象在数据库中是否存在,然后调用相应的方法。
  2. 如果传入该方法的是一个脱管对象,那么这个方法就会执行update操作,如果传入该方法的是一个临时对象,那么这个方法就会执行insert操作。
6. merge方法 【merge】
  1. 新new一个对象,如果该对象设置了ID,则这个对象就当作游离态处理:
    ⌂ 当ID在数据库中不能找到时,用update的话肯定会报异常,然而用merge的话,就会insert
    ⌂ 当ID在数据库中能找到的时候,update与merge的执行效果都是更新数据,发出update语句;
  2. 如果没有设置ID的话,则这个对象就当作瞬态处理:用update的话,由于没有ID,所以会报异常,merge此时则会保存数据,根据ID生产策略生成一条数据;
    在这里插入图片描述
    在这里插入图片描述
    merge和saveOrUpdate方法区别在于:merge方法是把我们提供的对象转变为托管状态的对象;而saveOrUpdate则是把我们提供的对象变成一个持久化对象;说的通俗一点就是:saveOrUpdate后的对象会纳入session的管理,对象的状态会跟数据库同步,再次查询该对象会直接从session中取,merge后的对 象不会纳入session的管理,再次查询该对象还是会从数据库中取。
7. delete() 方法 【Delete】
  1. Session 的 delete() 方法既可以删除一个游离对象, 也可以删除一个持久化对象
  2. Session 的 delete() 方法处理过程
    a 计划执行一条 delete 语句
    b 把对象从 Session 缓存中删除, 该对象进入删除状态.
  3. Hibernate 的 cfg.xml 配置文件中有一个 hibernate.use_identifier_rollback 属性, 其默认值为 false, 若把它设为 true, 将改变 delete() 方法的运行行为: delete() 方法会把持久化对象或游离对象的 OID 设置为 null, 使它们变为临时对象
8. evict () 方法

从 session 缓存中把指定的持久化对象移除,对象从持久化状态变为脱管状态。
Session中的clear是完成将session中的缓存清除。而evcit则是清除缓存中某个持久化的对象。即只把某个持久化的对象从缓存中移除。

猜你喜欢

转载自blog.csdn.net/qq_40803626/article/details/89413284