zoukankan      html  css  js  c++  java
  • Hibernate操作和保存方式

    Session API

    【Java Hibernate 之 CRUD 操作】http://www.codeceo.com/article/java-hibernate-crud.html
     
    【Session的入门常用方法】
    Query query = session.createQuery(hql):利用hql查询语句查询;
    Criteria critera = session.createCriteria(Class clazz);
    Transaction tx = session.beginTransaction();     //开始事务;tx.commit()提交事务;
    session.close();//关闭Session,此后被session管理的持久化对象变为脱管状态;
    session.save(Object obj);    //添加
    session.update(Object obj);     //更新
    session.delete(Object obj);    //删除
    Object obj = session.get(Class clazz,Serialiazble id);    //根据主键查找记录并返回;
    Object obj = session.load(Class clazz,Serializable id);    //和get方法效果一样,但是是懒加载,即在不使用他之前他不会返回对象;
     
     

    游离对象

    【临时状态transient、持久状态persistent和游离状态detached 】
     
    【游离对象】是由持久化对象转变过来的,因此可能在数据库中还存在对应的记录 。从持久化的数据转化而来。比如session关闭或者从session里delete这个对象。
            原来同Session有关联关系,但当下却没有关联关系了,这样的对象就是detached的对象。
            session的update()或者saveOrUpdate()方法,重新将该detached对象同相应的seesion建立关联关系。
     
    【临时对象】在数据库中没有对应的记录。 和hibernate session无关。事物提交也不能改变数据库对应的数据

            Transient对象指的是新建的持久化类的实例,它还从未同Hibernate的任何Session有过关联关系。

            persist()或者save()方法,将transient对象变成persistent对象。

    (1)当通过get或load方法得到的po对象它们都处于persistent,但如果执行delete(po)时(但还没执行事务),该 po状态就处于detached, (表示和session脱离关联),因delete而变成游离态可以通过save或saveOrUpdate()变成持久态
    (2)当一个session执行close()或clear()、evict()之后,session缓存中的persistent的po对象也变成detached,此时持久对象会变成脱管对象,此时该对象虽然具有数据库识别值,但它已不在HIbernate持久层的管理之下。

    update()

     

    saveorupdate()如果传入的对象在数据库中有就做update操作,如果没有就做save操作。

    save()在数据库中生成一条记录,如果数据库中有,会报错说有重复的记录。

    update()就是更新数据库中的记录 主键在saveorupdate()方法中是起着关键作用的,只有这个主键的值不为空的时候才进行insert还是update的判断,否则直接insert若主键不为空,就可以进行saveorupdate()操作了。 saveOrUpdate是当你一个pojo对象在不确定的情况下使用的,目的在于当这个对象存在的时候就将其状态改变成现在这个状态,如果不存在就使其持久化保存现在这个状态,也就是说不论怎样就是要有这个对象 save是返回插入数据的主见的,而saveOrUpdate是void

    save方法更适用于确定了是要插入,而且需要得到插入数据的主键

    而saveOrUpdate更倾向于不缺定是插入还是更新,而且你不需要得到他的主键

    另一方面,如果你无法确定你要插入或更新的对象是不是持久态或游离态时。如果你save一个持久态或更新一个游离态,这都是有问题的,此时你就要用到saveOrUpdate

    总体来说,如果你能确定你即将操作对象的状态,则不需要用saveOrUpdate

    【update()和flush区别?】

    Hibernate update操作的是在自由态或脱管状态(因session的关闭而处于脱管状态)的对象,而flush是操作的在持久状态的对象。
    默认情况下,一个持久状态的对象的改动(包含set容器)是不需要update的,只要你更改了对象的值,等待Hibernate flush就自动更新或保存到数据库了。
    (1) 调用某些查询的和手动flush(),session的关闭、SessionFactory关闭结合。get()一个对象,把对象的属性进行改变,把资源关闭。
    (2)transaction commit的时候(包含了flush) 。

     

    【update()和saveOrUpdate()的区别?】

    (1)update() 更新,没有主键会报错的,saveOrUpdate() 保存或更新, 没有主键就执行插入。
    (2)Update:是对暂态(transient )或是只是脱管(detached)的更新操作,对于暂态对象的更新操作通常不产生效果,对于脱管对象是做了同步的操作,即数据库的数据发生变化并且对象状态也成为托管对象
    SaveOrUpdate : 也是对暂态(transient )或是只是脱管(detached)的进行操作,至于是插入还是更新,则要根据(identifier)id 中指定的一些具体条件来分析,如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象 。
    (3)如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate(po)不做任何事
    如果savaOrUpdate(给定id的新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个NonUniqueObjectException异常 :a different object with the same identifier value was already associated with the session。

     

    【update()和merge()区别?】

    前面说过update,基本merge和update一样。但如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象覆盖session已有的持久实例
    (1)当我们使用update的时候,执行完成后,会抛出异常
    (2)但当我们使用merge的时候,把处理自由态的po对象A的属性copy到session当中处于持久态的po的属性中,执行完成后原来是持久状态还是持久态,而我们提供的A还是自由态。

    load()和get()的区别

    Object Session.load(Class arg0, Serializable arg1) throws HibernateException

        * arg0:需要加载对象的类,例如:User.class

        * arg1:查询条件(实现了序列化接口的对象):例"4028818a245fdd0301245fdd06380001"字符串已经实现了序列化接口。

        * 此方法返回类型为Object,但返回的是代理对象。

        * 执行此方法时不会立即发出查询SQL语句。只有在使用对象时,它才发出查询SQL语句,加载对象。

        * 因为load方法实现了lazy(称为延迟加载、赖加载)

        * 延迟加载:只有真正使用这个对象的时候,才加载(才发出SQL语句)

        * hibernate延迟加载实现原理是代理方式。

        * 采用load()方法加载数据,如果数据库中没有相应的记录,则会抛出异常对象不找到(org.hibernate.ObjectNotFoundException)

    Hibernate两种加载数据方式的区别:

        get()方法默认不支持lazy(延迟加载)功能,而load支持延迟加载

        get()方法在查询不到数据时,返回null,而load因为支持延迟加载,只有在使用对象时才加载,所以如果数据库中不在数据load会抛出异常(org.hibernate.ObjectNotFoundException)。

    get()和load()只根据主键查询,不能根据其它字段查询,如果想根据非主键查询,可以使用HQL


    如果在缓存中没有找到相应的对象,get将会直接访问数据库并返回一个完全初始化好的对象,而这个过程有可能会涉及到多个数据库调用;

    而load方法在缓存中没有发现对象的情况下,只会返回一个代理对象,只有在对象getId()之外的其它方法被调用时才会真正去访问数据库,这样就能在某些情况下大幅度提高性能。


    Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。其区别在于:

    如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个ObjectNotFoundException。


    Load方法可返回实体的代理类实例,而get方法永远直接返回实体类。


    load方法可以充分利用内部缓存和二级缓存中的现有数据,而get方法则仅仅在内部缓存中进行数据查找,如没有发现对应数据,将越过二级缓存,直接调用SQL完成数据读取。

    Session在加载实体对象时,将经过的过程:

    首先,Hibernate中维持了两级缓存。

    第一级缓存由Session实例维护,其中保持了Session当前所有关联实体的数据,也称为内部缓存。

    而第二级缓存则存在于SessionFactory层次,由当前所有由本 SessionFactory构造的Session实例共享。

    出于性能考虑,避免无谓的数据库访问,Session在调用数据库查询功能之前,会先在缓存中进行查询。首先在第一级缓存中,通过实体类型和id进行查找,如果第一级缓存查找命中,且数据状态合法,则直接返回。
    之后,Session会在当前“NonExists”记录中进行查找,如果“NonExists”记录中存在同样的查询条件,则返回null。 “NonExists”记录了当前Session实例在之前所有查询操作中,未能查询到有效数据的查询条件(相当于一个查询黑名单列表)。如此一来,如果 Session中一个无效的查询条件重复出现,即可迅速作出判断,从而获得最佳的性能表现。

    对于load方法而言,如果内部缓存中未发现有效数据,则查询第二级缓存,如果第二级缓存命中,则返回。


    如在缓存中未发现有效数据,则发起数据库查询操作(Select SQL),如经过查询未发现对应记录,则将此次查询的信息在“NonExists”中加以记录,并返回null。
    根据映射配置和Select SQL得到的ResultSet,创建对应的数据对象。
    将其数据对象纳入当前Session实体管理容器(一级缓存)。
    执行Interceptor.onLoad方法(如果有对应的Interceptor)。
    将数据对象纳入二级缓存。
    如果数据对象实现了LifeCycle接口,则调用数据对象的onLoad方法。
    返回数据对象。

    save、persist和saveOrUpdate这三个方法的不同之处?

    都是用于将对象保存到数据库中的方法。

    save()只能INSERT记录

    saveOrUpdate()可以进行 记录的INSERT和UPDATE。

    save()的返回值是一个Serializable对象

    persist()方法返回值为void。

     

    getCurrentSession()与openSession()

    都通过Hibernate的SessionFactory获得:

    1.getCurrentSession创建的session会和绑定到当前线程,而openSession不会。

    2.getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭。



    对于getCurrentSession()方法: 
           (1)其所在方法必须进行事务控制 
           (2)Session在第一次被使用的时候,或者第一次调用getCurrentSession()的时候,其生命周期就开始。然后它被Hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,Hibernate也会把Session从当前线程剥离,并且关闭它。假若你再次调用getCurrentSession(),你会得到一个新的Session,并且开始一个新的工作单元。     
       
    对于openSession()方法: 
            这个方法一般在spring与Hibernate的集成中不直接使用,它就是打开一个session,并且这个session与上下文无关,如果对其所在方法进行事务控制,会发现不起作用,原因就是前面提到的,事务控制必须确保是同一个连接,而openSession()打开的session与上下文无关。
     
    这个方法与getSession(),getCurrentSession()以及getHibernateTemplate()等方法的区别在于:后面的几个方法spring可以对其进行控制。
    如果对它们所在的方法进行事务控制,spring可以确保是同一个连接,而openSession()方法,spring无法对其进行控制,所以事务也不会起作用。

    lock()

            Session的lock()方法重建了关联关系却并没有同数据库进行同步和更新。因此,你在使用lock()方法时一定要多加小心。顺便说一下,在进行关联关系重建时,你可以随时使用Session的update()方法同数据库进行同步。有时这个问题也可以这么来问:Session的lock()方法和update()方法之间有什么区别?。


    【lock()方法与update()方法的区别】
    在执行lock()方法时,会立即使用查询语句查询版本号进行版本检查,并不会执行一个update操作。 
     
    而update()方法,并不会进行版本检查,直到session.flush()时候,会先进行版本检查,再进行更新操作。
     
    这两个方法都把一个游离对象与一个session实例关联起来。
     
     
    lock是把一个没有更改过的脱管状态的对象变成持久状态
    1.调用lock把对象从脱管状态变成持久状态
    2.更改持久状态的对象的内容
    3.等待flush或者手动flush 
     

     
    lock和update区别
    update是把一个已经更改过的脱管状态的对象变成持久状态
    lock是把一个没有更改过的脱管状态的对象变成持久状态(针对的是因Session的关闭而处于脱管状态的po对象(2),不能针对因delete而处于脱管状态的po对象)
    对应更改一个记录的内容,两个的操作不同:
    update的操作步骤是:
    (1)属性改动后的脱管的对象的修改->调用update
    lock的操作步骤是:
    (2)调用lock把未修改的对象从脱管状态变成持久状态-->更改持久状态的对象的内容-->等待flush或者手动flush

    SessionFactory

    SessionFactory有什么作用? SessionFactory是线程安全的吗?

        这也是Hibernate框架的常见面试问题。顾名思义,SessionFactory就是一个用于创建Hibernate的Session对象的工厂。SessionFactory通常是在应用启动时创建好的,应用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是 线程安全的,所以多个线程可同时使用同一个SessionFactory。Java JEE应用一般只有一个SessionFactory,服务于客户请求的各线程都通过这个工厂来获得Hibernate的Session实例,这也是为什么SessionFactory接口的实现必须是线程安全的原因。还有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是不可变的,一旦创建好后就不能对其进行修改了。

    hibernate的各种保存方式的区别(save,persist,update,saveOrUpdte,merge,flush,lock)及对象的三种状态


    hibernate的保存


    hibernate对于对象的保存提供了太多的方法,他们之间有很多不同,这里细说一下,以便区别。
    一、预备知识
    对于hibernate,它的对象有三种状态,transient、persistent、detached
    下边是常见的翻译办法:
    transient:瞬态或者自由态
    (new DeptPo(1,”行政部”,20,”行政相关”),该po的实例和session没有关联,该po的实例处于transient)
    persistent:持久化状态
    (和数据库中记录想影射的Po实例,它的状态是persistent, 通过get和load等得到的对象都是persistent)
    detached:脱管状态或者游离态
    (1)当通过get或load方法得到的po对象它们都处于persistent,但如果执行delete(po)时(但不能执行事务),该po状态就处于detached, (表示和session脱离关联),因delete而变成游离态可以通过save或saveOrUpdate()变成持久态
    (2)当把session关闭时,session缓存中的persistent的po对象也变成detached
    因关闭session而变成游离态的可以通过lock、save、update变成持久态
    持久态实例可以通过调用 delete()变成脱管状态。
    通过get()或load()方法得到的实例都是持久化状态的。
    脱管状态的实例可以通过调用lock()或者replicate()进行持久化。

    save()和persist()将会引发SQL的INSERT,delete()会引发SQLDELETE,
    而update()或merge()会引发SQL UPDATE。对持久化(persistent)实例的修改在刷新提交的时候会被检测到,它也会引起SQL UPDATE。
    saveOrUpdate()或者replicate()会引发SQLINSERT或者UPDATE


    二、save 和update区别
    把这一对放在第一位的原因是因为这一对是最常用的。
    save的作用是把一个新的对象保存
    update是把一个脱管状态的对象或自由态对象(一定要和一个记录对应)更新到数据库

    三、update 和saveOrUpdate区别
    这个是比较好理解的,顾名思义,saveOrUpdate基本上就是合成了save和update,而update只是update;引用hibernate reference中的一段话来解释他们的使用场合和区别
    通常下面的场景会使用update()或saveOrUpdate(): 
    程序在第一个session中加载对象,接着把session关闭 
    该对象被传递到表现层 
    对象发生了一些改动 
    该对象被返回到业务逻辑层最终到持久层 
    程序创建第二session调用第二个session的update()方法持久这些改动

    saveOrUpdate(po)做下面的事: 
    如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate不做任何事 
    如果savaOrUpdate(新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个异常 
    org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.itfuture.www.po.Xtyhb#5]
    saveOrUpdate如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象

    四、persist和save区别
    这个是最迷离的一对,表面上看起来使用哪个都行,在hibernate reference文档中也没有明确的区分他们.
    这里给出一个明确的区分。(可以跟进src看一下,虽然实现步骤类似,但是还是有细微的差别)
    主要内容区别:
    1,persist把一个瞬态的实例持久化,但是并"不保证"标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。

    2,save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert

    五、saveOrUpdate,merge和update区别
    比较update和merge
    update的作用上边说了,这里说一下merge的
    如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象覆盖session已有的持久实例 
    (1)当我们使用update的时候,执行完成后,会抛出异常 
    (2)但当我们使用merge的时候,把处理自由态的po对象A的属性copy到session当中处于持久态的po的属性中,执行完成后原来是持久状态还是持久态,而我们提供的A还是自由态

    六、flush和update区别
    这两个的区别好理解
    update操作的是在自由态或脱管状态(因session的关闭而处于脱管状态)的对象//updateSQL
    而flush是操作的在持久状态的对象。
    默认情况下,一个持久状态的对象的改动(包含set容器)是不需要update的,只要你更改了对象的值,等待hibernate flush就自动更新或保存到数据库了。hibernate flush发生在以下几种情况中:
    1, 调用某些查询的和手动flush(),session的关闭、SessionFactory关闭结合 
    get()一个对象,把对象的属性进行改变,把资源关闭。
    2,transaction commit的时候(包含了flush)


    八、clear和evcit的区别
    clear完整的清除session缓存
    evcit(obj)把某个持久化对象从session的缓存中清空。

  • 相关阅读:
    数学之美系列十八 矩阵运算和文本处理中的分类问题
    数学之美系列一 统计语言模型
    数学之美系列十三 信息指纹及其应用
    数学之美系列十六 谈谈最大熵模型
    数学之美系列十五 繁与简 自然语言处理的几位精英
    数学之美系列十七 谈谈搜索引擎作弊问题(Search Engine AntiSPAM)
    数学之美系列三 隐含马尔可夫模型在语言处理中的应用
    数学之美系列十四 谈谈数学模型的重要性
    数学之美系列十二 余弦定理和新闻的分类
    数学之美系列十一 Google 阿卡 47 的制造者阿米特.辛格博士
  • 原文地址:https://www.cnblogs.com/lsx1993/p/4620004.html
Copyright © 2011-2022 走看看