黑马程序员技术交流社区

标题: hibernate 的transaction和 session问题 [打印本页]

作者: 王海龙    时间: 2013-2-23 23:37
标题: hibernate 的transaction和 session问题
用的SSH框架,事务切到service层, 在service取出一个用户列表,在action中循环此列表修改每个用户的角色id属性为角色名称后 , 数据库就变了呀 !!

在网上搜索了好久 说session关闭的时候会吧持久对象更新到数据库中,

但是自己做了一个例子
  1. Transaction tx = session.beginTransaction();
  2.         Query query = session.createQuery("from Test01");
  3.         query.setFirstResult(begin);
  4.         query.setMaxResults(count);
  5.         List<Test01> l =  (List<Test01>)query.list();
  6.         for(Test01 u : l){
  7.             u.setPwd("1");
  8.         }
  9.          
  10.         tx.commit();
  11.         for(Test01 u : l){
  12.             System.out.println(u);
  13.             u.setPwd("22222");
  14.             session.update(u);
  15.         }
  16.         session.flush();
  17.         session.close();
复制代码
修改后数据库中 pwd却是"1" 不是"22222" 为什么?

作者: 杨杨    时间: 2013-2-24 10:05
tx.commit();
放在for循环 下面 hibernate 的几种状态
我搜的希望对你有帮助
Hibernate对象状态
临时(Transient) - 由new操作符创建,且尚未与Hibernate Session 关联的对象被认定为临时(Transient)的。临时(Transient)对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。 如果临时(Transient)对象在程序中没有被引用,它会被垃圾回收器(garbage collector)销毁。 使用Hibernate Session可以将其变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)

持久(Persistent) - 持久(Persistent)的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。 持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的Session作用范围内。 Hibernate会检测到处于持久(Persistent)状态的对象的任何改动,在当前操作单元(unit of work)执行完毕时将对象数据(state)与数据库同步(synchronize)。 开发者不需要手动执行UPDATE。将对象从持久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行DELETE语句。

游离(Detached) - 与持久(Persistent)对象关联的Session被关闭后,对象就变为游离(Detached)的。 对游离(Detached)对象的引用依然有效,对象可继续被修改。游离(Detached)对象如果重新关联到某个新的Session上, 会再次转变为持久(Persistent)的(在Detached其间的改动将被持久化到数据库)。 这个功能使得一种编程模型,即中间会给用户思考时间(user think-time)的长时间运行的操作单元(unit of work)的编程模型成为可能。 我们称之为应用程序事务,即从用户观点看是一个操作单元(unit of work)。

Hibernate中对象的游离状态是指Session关闭之后,持久化对象变成离线对象,离线对象就不能同数据库同步,也不再受Hibernate管理。操作 处于游离态对象 经常会报 session已关闭的错误。

假设场景:
有两个类, Team, Person. 映射关系是Team一对多Person, 采用lazy fetch策略。
session begin
Team t = *Dao.get()
session end
t.getPersons()// 出错
如果是用spring管理session的情况,事务外操作t.getPerons()也跟上面情况一样。
这种情况在生产环境多表现为在jsp页面操作 t对象时出错。

解决方法:
1. 取消lazy fetch策略
缺点:会导致过多的数据库访问,因为是一对多的情况。
2. 在事务内就先把关联的对象取出
缺点:会导致service层方法不统一,因为要分开取出与不取出的情况。
3. 使用spring的 openSessionInview机制
缺点: session打开的时间比较长, 使用不好可能会导致out of memory



一个游离态的对象转换为持久战态,有以下几种方法:

1、session.saveOrUpdate(object)。这语句会把游离态的PO转为持久态的PO并提交给数据库

2、session.merge(object)。这语句会把游离态的PO转为持久态的PO,并进行合并操作。

3、session.lock(object, LockMode.NONE)。这语句只会把游离态的PO转为持久态PO,不作其他操作。不过,PO必须是没有修改过的,这方法挺适合做一个应用层


作者: 杨杨    时间: 2013-2-25 14:13
杨杨 发表于 2013-2-24 10:05
tx.commit();
放在for循环 下面 hibernate 的几种状态
我搜的希望对你有帮助

是不是没有代码就不加技术分啊
作者: 杨杨    时间: 2013-2-25 14:18
Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Test01");
        query.setFirstResult(begin);
        query.setMaxResults(count);
        List<Test01> l =  (List<Test01>)query.list();
        for(Test01 u : l){
            u.setPwd("1");
        }
         
               for(Test01 u : l){
            System.out.println(u);
            u.setPwd("22222");
            session.update(u);
        }
tx.commit();

        session.flush();
        session.close();
楼主这样试试
作者: 陈丽莉    时间: 2013-2-25 20:36
试试楼下的方法,不行的话继续追问, ok的话请将帖子改成【已解决】。
作者: 张庚    时间: 2013-3-1 15:18
第十行的时候你的事物已经提交  就更新到数据库去了 下面的美提交没有更新到数据库
作者: 陈丽莉    时间: 2013-3-1 18:44
杨杨 发表于 2013-2-25 14:13
是不是没有代码就不加技术分啊

你回答的没到点子上啊,看你辛苦才加金币的~
作者: 何伟    时间: 2013-3-3 18:43
看来这里的版主都是高手啊,,,!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2