zoukankan      html  css  js  c++  java
  • Hibernate中session的save方法以及缓存的清理

     Session的save()方法使一个临时对象转变为持久化对象。例如以下代码保存一个Customer对象:

            Customer customer = new Customer();
            customer.setId(new Long(9)); // 为Customer临时对象设置OID是无效的
            customer.setName("Tom");
            Session session = sessionFactory.openSession();
            Transaction tx = session.beginTransaction();
            session.save(customer);
            session.close();

    Session的save()方法完成以下的操作:

        (1)把Customer对象加入到缓存中,使它变为持久化对象。

        (2)选用映射文件指定的标识符生成器为持久化对象分配惟一的OID。Customer.hbm.xml文件中<id>元素的<generator>子元素指定标识符生成器:(此配置文件跟Customer类放在一起,generator的class还有另外一个取值“native”)

    <id name="id" column="ID">
                <generator class="increment"/>
            </id>
    

      

    以上程序试图通过setId()方法为Customer临时对象设置OID是无效的。假如起初CUSTOMERS表中没有记录,那么执行完save()方法后,Customer对象的ID为1。如果希望由程序来为Customer对象指定OID,可以调用save()的另一个重载方法:  

    save(customer, new Long(9));

        以上save()方法的第二参数显示指定Customer对象的OID。这种形式的save()方法不推荐使用,尤其在使用代理主键的场合,不应该由程序为持久化对象指定OID。

        (3)计划执行一个insert语句,把Customer对象当前的属性值组装到insert语句中:

     insert into CUSTOMERS(ID, NAME, ......) values(1, 'Tom', ......);

    值得注意的是,save()方法并不立即执行SQL insert语句只有当Session清理缓存(事务提交时先清理缓存,transaction.commit())时,才会执行SQL insert语句。如果在save()方法之后,又修改了持久化对象的属性,这会使得Session在清理缓存时,额外执行SQL update语句。以下两段代码尽管都能完成相同的功能,但是左边代码仅执行一条SQL insert语句,而右边代码执行一条SQL insert和一条SQL update语句。上边代码减少了操作数据库的次数,具有更好的运行性能

     Customer customer = new Customer();         Customer customer = new Customer();
            // 先设置Customer对象的属性,再保存它       session.save(customer);
            customer.setName("Tom");                    // 先保存Customer对象,再修改它的属性
            session.save(customer);                     customer.setName("Tom");
            transaction.commit();                       transaction.commit();//此时清理缓存

     Hibernate通过持久化对象的OID来维持它和数据库相关记录的对应关系。当Customer对象处于持久化状态时,不允许程序随意修改它的OID,例如:

    Customer customer = new Customer();
            session.save(customer);
            customer.setId(new Long(100)); // 抛出HibernateException
            transaction.commit();

    以上代码会导致Session在清理缓存时抛出异常。

    注意:无论Java对象处于临时状态、持久化状态还是游离状态,应用程序都不应该修改它的OID。因此,比较安全的做法是,在定义持久化类时,把它的setId()方法设为为private类型,禁止外部程序访问该方法。

    Session的save()方法是用来持久化一个临时对象的。在应用程序中应该把持久化对象或游离对象传给save()方法。例如以下代码两次调用了Session的save()方法,第二次传给save()方法的Customer对角处于持久化状态,这步操作其它是多余的:

      Customer customer = new Customer();
            session.save(customer);
            customer.setName("Tom");
            session.save(customer); // 这步操作是多余的
           transaction.commit();

     在例如以下代码把Customer游离对象传给session2的save()方法,session2会把它当做临时对象处理,再次向数据库中插入一条Customer记录:

    Customer customer = new Customer();
            customer.setName("Tom");
            Session session1 = sessionFactory.openSession();
            Transaction tx1 = session1.beginTransaction();
            session1.save(customer); // 此时Customer对象的ID变为1
            tx1.commit();
            session1.close(); // 此时Customer对象变为游离对象
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            session2.save(cutomer); // 此时Customer对象的ID变为2
            tx2.commit();
            session2.close();

    尽管以上程序代码能正常运行,但是会导致CUSTOMERS表中有两条代表相同业务实体的记录,因此不符合业务逻辑。

     ------------------------------------------------------------------------------------------------------

    在默认情况下,session会在下面的时间点清理缓存

    当应用程序调用net.sf.hibernate.Transactioncommit()方法时,commit()方法先清理缓存,然后再看数据库提交事务

    当调用sessionfind()或者iterator()时,如果缓存中持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能反映持久化对象的最新状态。

    当应用程序显式调用sessionflush()方时。

    Session的setFlushMode()方法用于设定清理缓存的时间点。FlushMode类定义了三种不同的清理模式:FlushMode.AUTO、FlushMode.COMMIT和FlushMode.NEVER。例如,以下代码显示把清理模式设为FlushModo.Commit:

      session.setFlushMode(FlushMode.COMMIT);

                                                                                                 三种清理模式

     清理缓存的模式

     Session的查询方法

     Session的commit()方法

     Session的flush()方法

     FlushMode.AUTO  清理  清理  清理
     FlushMode.COMMIT  不清理  清理  清理
     FlushMode.NEVER  不清理  不清理  不清理

     FlushMode.AUTO是默认值,这也是优先考虑的清理模式,它会保证在整个事务中,数据保持一致。如果事务公包含查询数据库的操作,而不会修改数据库的数据,也可以选用FlushMode.COMMIT模式,这可以避免在执行Session查询方法时先清理缓存,以稍微提高应用程序的性能。

        在大多数情况下,应用程序不需要显示调用Session的flush()方法,flush()方法适用于以下场合:

        (1)插入、删除或更新某个持久化对象会引发数据库中的触发器。假定向CUSTOMERS表新增一条记录时会引发一个数据库触发器,在应用程序中,通过Session的save()方法保存了一个Customer对象,应用随后调用Session的flush()方法:

    session.save(customer);
    
          session.flush();

    Session的flush()方法会立即执行insert语句,该语句接着引发相关的触发器工作。

        (2)在应用程序中混合使用Hibernate API和JDBC API。

        (3)JDBC驱动程序不健壮,导致Hibernate在自动清理缓存的模式下无法正常工作。

     我们知道,如果一味的让新的数据放到缓存中去,那我们计算机肯定会内存崩溃。所以进行必要的缓存清除还是很有必要的。 
    下面我们分析一下几种方法: 
    1、

    for(int i=0;i<1000;i++){   
    Order order = new Order();   
    order.setId();   
    session.save(order);   
    if(i%100==0){   
    session.flush();   
    session.clear();   
    }   
    }  

    2 、

    for(int i=0;i<1000;i++){   
    Order order = new Order();   
    order.setId();   
    session.save(order);   
    session.evict();//清除session缓存   
    SessionFactory.evict();//清除二级缓存   
    }  

     注意:一级缓存只在同一个session中有效,二级缓存是全局性质的

    一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据。
    二级缓存就是SessionFactory级别的缓存,顾名思义,就是查询的时候会把查询结果缓存到二级缓存中,如果同一个sessionFactory创建的某个session执行了相同的操作,hibernate就会从二级缓存中拿结果,而不会再去连接数据库。(
    Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分为两类:内置缓存和外置缓存。Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。

    evict()方法 
      该方法于上一个方法不同,它只能用于处理单个对象的清除工作。 

    clear()方法 
      我们可以在session-factory标签下创建property标签,name属性为hibernate.jdbc.batch_size,值为我们想要设定的数字,假如为100,下一步当我们执行操作flush()发送SQL语句时候调用session.clear()方法,就可以实现清除缓存的效果了。 

     

  • 相关阅读:
    用js添加网页标题时,在QQ里无效,标题栏空白
    用css3的@keyframes里设置transform:rotate(); 当控制动画暂停:animation-play-state:paused暂停,在微信和safari里无效
    Python可变序列中的一些坑,记得多注意
    你知道?Python 中的序列类型支持哪些公共操作吗?
    用 python print() 函数实现的三个特效
    教你使用python生成器重构提取数据方法,来优化你的爬虫代码
    python中主线程与子线程的结束顺序,你知道吗?
    python装饰器实现对异常代码出现进行自动监控
    Python教程:高效率遍历文件夹寻找重复文件
    python教程: filter()和reduce()函数用法详解
  • 原文地址:https://www.cnblogs.com/90zyh/p/3027153.html
Copyright © 2011-2022 走看看