zoukankan      html  css  js  c++  java
  • 由一个bug 引出的 hibernate 三种状态

    (一)问题的引出:

    假如现在我想把书名给改了,想改成struts2,book.setName("Struts2开发");
    以前我们是要session.update(book)来完成修改。现在我们这里可以不用写update了,它可以自动完成数据的更新。

    03-Hibernate持久态对象自动更新数据库


    http://blog.sina.com.cn/s/blog_981ee5d80102w85a.html

    为什么会有自动更新数据库的能力

    因为它是依赖了hibernate的一级缓存区域的


    http://blog.csdn.net/wangyang1354/article/details/50602658


        



    (二)

    之前一直没发现这个问题,后来是因为我的导航栏数据库中数据发生变动后,产生菜单的时候又update了一遍数据库中的数据,使得部分数据值为空了,当时觉得很奇怪,后来仔细看了下log4j打印的日志发现其中有更新的动作,在代码中将数据库中获取到的对象set一个对象属性时,数据库就update了,但是这个问题是怎么产生的呢?


    问题重述

    [java] view plain copy
    1. Set<User> users = new HashSet<User>();  
    2. User user = null;  
    3. for(int i = 0; i < 10; i++){  
    4.     user = new User();  
    5.     user.setUserName("wy" + i);  
    6.     users.add(user);  
    7. }  
    8. Company company = userDao.getCompany();  
    9. company.setUsers(users);  

    类似上面的代码,company是刚刚从数据库中获取到的,然后我构造了一个User对象的Set集合,然后在这里直接setUsers的时候就出现了更新数据库的动作,当然这段代码只是示例并不是实际的项目代码。


    问题在哪里

          Hibernate分为三种基本的状态:游离态、自由态(临时状态)、持久态。
          持久化状态:与session关联并且和在数据库有数据,已经持久化了并且在数据库的缓存当中了。
          我这里的这个对象应该是持久化状态的对象然后我直接构造了一个user对象的set集合,同时对这个对象进行set操作,那么缓存Session中的数据发生改变,那么接着数据库也会跟着进行相应的改变。所以就执行了update的更新操作。


    怎么解决

         其他两种状态:
         1. 临时状态:就是直接new出来的对象,既没有持久化到数据库中去,也没有在session当中。
         2. 游离状态:在Session中没有了,但是已经持久化到了数据库当中。
         
         那么这个地方怎么解决呢?
         1.如果这个对象(例子中的company)本身不需要用的话,可以直接new一个Company的对象出来然后再setUsers这个时候因为不是Session中的数据,那么不会因为对象的属性发生改变而同步到数据库中去。
         2. 如果这个对象(例子中的company)要用的到,那么,在set之前可以先将其转为游离态,这样的话会用到session的几个方法:close、clear、evict。
         close方法:关闭session这样这个对象肯定是游离态了,因为session已经关闭了,但是往往我们实际的开发过程中,session在后面是要用的到的,所以这个方法可行,但是不一定用得上,分清具体的情况。
         clear方法:将session中的所有的对象全部清除出缓存,这个方式有点劳师动众,不过session清除了全部的对象之后自然就会变为游离态了,这样做不是很好吧我感觉。
         evict方法:将某一个对象清除出缓存session,这个方法是很好的实现方式,推荐使用。调用的时候是这样的,session.evict(Object obj);这样就可以了。


    知识扩充:深入理解Hibernate三种状态


    状态之间如何转换


    1. Save和Update:save的时候是将自由态的对象持久化到数据库中,而update的时候一般是将游离态的对象持久化到数据库中去。

    2. update、saveOrUpdate、merge:saveOrUpdate的作用是当Session中存在要操作的对象的时候,抛出异常信息,当不存在的时候,如果这个对象没有持久化标识属性,那么将这个对象save,如果这个对象有持久化标识属性的话,那么直接update就可以了。对于单纯的update来说,程序会在一个Session中加载对象,然后将这个对象关闭,然后这个对象发生变化之后,再update的时候就会打开另一个Session将对象持久化到数据库中去。merge的话是当Session中存在要操作的对象的时候,不会抛出异常而是直接将这个对象的数据拷贝到Session中持久态的对象中去,这样对象还是维持着原来的状态。

    3.persist和save:都是用来保存临时对象到数据库的,但是persist并不保证对象的主键立即被创建好,有可能推迟到flush的时候。但是save的时候会立即创建好的,所以save的时候一般可以通过对象拿到主键值。

    4. flush和update:update的时候对象多是游离态的对象,也就是说数据库中已经存在了,但是并不在Session中的对象通过update会更新到数据库当中去。而flush是将本来持久态的数据更新到数据库中去。

    5. lock是将一个没有更改过的托管的对象转为持久态的对象,但是他不能针对那些delete后的托管的对象。

    代码实例分析


    [java] view plain copy
    1. User user = new User();  
    2. user.setName("wy");  
    3. //目前还是一个临时对象  
    4.   
    5. Session session = sessionFactory.openSession();  
    6. Tansaction tx = session.beginTansaction();  
    7. //目前还是一个临时对象  
    8. session.save(user);  
    9. //user处于持久态了  
    10. tx.commit();  
    11. session.close();// 游离态了  



    (三)

    https://www.cnblogs.com/yangy608/p/4073941.html

    案例:

    TInfCustomer cus = (TInfCustomer) this.baseDao.getOne(helper);

    cus.setXXX

    cus .setXXX

    不调用update也写入数据库

    原因:

    hibernate在每个session里都会做些处理,比如把查询过的对象缓存起来什么,这个时候这些对象的实例是和数据库保持关联的,hibernate会记录session生命周期内所有缓存对象的操作过程,最后都会反映到数据库去,也就是所谓的托管状态,所以才会有自动更新这种问题。只要每次都把查询到的对象用evict(或clear)清除(记得,是每次),那么就不会有托管状态的entity,也就不会有自动更新,但这不会影响(应该)update(或saveOrUpdate)操作,evict只是清楚实例与数据库的关联而已,不是清楚实例本身。 
     
    修改:baseDao.getCurrentSession().evict(arg0)





    (四)

  • 相关阅读:
    Django 项目试炼blog(8) -- 评论树的显示
    Django 项目试炼blog(7) -- 文章详情页2 -- 前端样式的继承与楼评论显示
    Django 项目试炼blog(6) -- 文章详情页1 -- 点赞功能
    Django 项目试炼blog(5) -- 个人站点的搭建
    Django 项目试炼blog(4)--blog主页的搭建以及admin的使用
    Django 项目试炼blog(3)--基于Form组件ajax用户注册
    Django 项目试炼blog(2)--用户登陆验证
    Django 项目试炼blog(1)
    Django 基于form与ajax发送文件
    Django 分页器制作
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106725.html
Copyright © 2011-2022 走看看