• Hibernate开发实践笔记--对象在set属性时更新了数据库问题


    目录(?)[+]

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


    问题重述

    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后的托管的对象。

    代码实例分析


      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();// 游离态了 
  • 相关阅读:
    洛谷P1724 东风谷早苗
    hdu 1001 Sum Problem
    洛谷 P1006 传纸条
    codevs 6116 区间素数
    LibreOJ #101. 最大流
    洛谷 P1455 搭配购买
    LibreOJ #119. 最短路 (堆优化dijkstra)
    LibreOJ #109. 并查集
    COGS.1200 ganggang的烦恼
    uoj #15. 【NOIP2014】生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/smallfa/p/6233586.html
Copyright © 2020-2023  润新知