hibernate 操控对象封装方法

来源:互联网 发布:wegame 知乎 编辑:程序博客网 时间:2024/05/16 17:36

1.save方法

Session 的 save() 方法使一个临时对象转变为持久化对象 
Session 的 save() 方法完成以下操作: 
1. 把 User对象加入到 Session 缓存中,使它进入持久化状态 
2. 选用映射文件指定的标识符生成器,为持久化对象分配唯一的 OID。在 使用代理主键的情况下,setId() 方法为 User对象设置 OID 是无效的。 
3. 计划在 flush 缓存的时候,执行一条 insert 语句。

注意: 
1. hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系。当 User 对象处于持久化状态时,不允许程序随意修改它的 ID,否则会报异常:org.hibernate.HibernateException: identifier of an instance of com.zeng2.model.User was altered from 17(持久化状态的原有值) to 100(新修改的值) 
。 
所以在实际开发中,我们应该将setId()设为private防止用户更改实体id 
2. 在一般完成持久化对象的初始化工作时,我们应先完成资源准备(设定成员属性值)后,再调用save方法。否则会增加额外的sql语句,如下所示:

//先设值再保存User user1 = new User();user1.setName("name1");session.save(user1);//Hibernate: insert into t_user2 (name, id) values (?, ?)//先保存再设值User user2 = new User();session.save(user2);user2.setName("name2");//Hibernate: insert into t_user2 (name, id) values (?, ?)//Hibernate: update t_user2 set name=? where id=? update t_user2 set name=? where id=?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2. persist方法

persist和save都能用来持久化对象,但它和user的区别是:当对一个 OID 不为 Null 的对象执行 save() 方法时,会把该对象以一个新的 oid 保存到数据库中;但执行 persist() 方法时会抛出一个异常。

//测试persist和save的区别User user = new User();user.setId(100);session.save(user);//执行Hibernate: insert into t_user2 (name, id) values (?, ?)User user2 = new User();user2.setId(200);session.persist(user2);//报异常org.hibernate.PersistentObjectException: detached entity passed to persist: com.zeng2.model.User
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3. get和load方法

  1. 相同点: 
    都可以根据跟定的 OID 从数据库中加载一个持久化对象
  2. 区别: 
    1. 当数据库中不存在与 OID 对应的记录时,load() 方法抛出 ObjectNotFoundException 异常,而 get() 方法返回 null。
    2. 两者采用不同的延迟检索策略:load默认使用懒加载策略,除非将相应对象的获取策略设为即时加载。而get只要调用了,都会立即从数据库中甲在数据。

4. update方法

使一个游离对象转变为持久化对象,并且计划在flush时执行一条 update 语句 
在一下情况使用会抛出异常: 
1. 当 update() 方法关联一个游离对象时,如果在 Session 的缓存中已经存在相同 OID 的持久化对象,会抛出异常 
2. 当 update() 方法关联一个游离对象时,如果在数据库中不存在相应的记录,也会抛出异常. 
下面是我们的测试代码:

//测试updateUser user = new User();session.update(user);//报异常:org.hibernate.TransientObjectException: The given object has a null identifier: com.zeng2.model.UserUser user = new User();user.setId(1);//数据库中存在的idsession.update(user);//Hibernate: update t_user2 set name=? where id=?User user = new User();user.setId(111111);//数据库中不存在的idsession.update(user);//报异常:org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1User user = session.get(User.class, 1);User user2 = new User();user2.setId(1);session.update(user2);//更新一个在session缓存中已存在的对象//报异常:org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.zeng2.model.User#1]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5. saveOrUpdate方法

Session 的 saveOrUpdate()可以看成是save和update的整合,两者形成有效互补。 
它的执行过程吐下图所示:

saveOrUpdate对象游离对象(yes),临时对象(no)更新对象保存对象yesno

我们常常根据id是否为null来判定来判断一个对象的状态,下面来看一个测试实例:

//测试saveOrUpdate//1. 临时对象User user = new User();session.saveOrUpdate(user);//Hibernate: insert into t_user2 (name, id) values (?, ?)//2. 设置id构造伪游离对象User user = new User();user.setId(1);//数据库存在此id对应记录session.saveOrUpdate(user);//Hibernate: update t_user2 set name=? where id=?//3. 构造id,但不存在于数据库,会报异常User user = new User();user.setId(111111);//数据库不存在此id对应记录session.saveOrUpdate(user);//org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

6. merge方法

把一个游离对象的属性复制到一个持久化对象中.先看我们的测试代码:

        //先尝试使用update方法用新对象更新Session缓存中已存在id标识为1的对象//      User user = session.get(User.class, 1);//      User user2 = new User();//      user2.setId(1);//      session.update(user2);        //报异常:org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.zeng2.model.User#1]        //测试merge        User user = session.get(User.class, 1);        System.out.println(user3.getName());//name        User user2 = new User();        user2.setId(1);        user2.setName("newName");        session.merge(user2);        System.out.println(user3.getName());//newName        System.out.println(user == user2);//false        System.out.println(user2 == user3);//false        System.out.println(user3 == user);//true        //Hibernate: update t_user2 set name=? where id=?        /*查看数据库,记录成功更新:        +----+---------+        | id | name    |        +----+---------+        |  1 | newName |        */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

从上面我们可以看出,当session存在特定id的对象时,我们尝试自己伪造一个相同id对象并通过update来对其持久化时,会出现错误.而我们使用merge时却能成功更新,下面我们结合这个例子来分析调用merge方法的运行流程:

1. 如果user2是一个游离对象(id不为null)

  1. 先到session缓存中查找id和user2相同的User,如果找到了(找到user),并将user2的值复制给user,在flush时执行update语句,从这里看,这就是我们操作更新的原因.还没完,它还会返回user的一个引用(这时候,user的值是user2复制完成后的值)所以打印时user3.getName=newName,并且user3 == user

  2. 如果没在session缓存中找到,会查询数据库有没相同的记录:

    1. 如果存在,则获取下来(设为oUser,此时未持久化对象),并将user2的属性复制到oUser中,同时返回oUser的引用到user3,并计划在flush时执行一条update语句更新数据库
    2. 如果不存在,则会新建一个对象(设为nUser),将user2的属性复制到这个nUser中,再调用save方法持久化nUser,并返回nUser的引用,此时nUser == user3 为true

2. 如果user2是一个临时对象(id为null)

新建一个对象(设为nUser),将user2的属性复制到这个nUser中,再调用save方法持久化nUser,并返回nUser的引用,此时nUser == user3 为true

根据这个流程分析,在整个过程中,我们的user2始终是非持久性对象.不像使用update,方法调用成功后,入参必定为持久化对象. 
下面是一张流程执行框图,能够加深我们的理解:

这里写图片描述

7. delete方法

Session 的 delete() 方法既可以删除一个游离对象,也可以删除一个持久化对象 
Session 的 delete() 方法处理过程: 
1. 计划执行一条 delete 语句(在flush时正式执行),把对象从 Session 缓存中删除,该对象进入删除状态。 
2. Hibernate 的 cfg.xml 配置文件中有一个 hibernate.use_identifier_rollback 属性,其默认值为 false,若把它设为 true,将改变 delete() 方法的运行行为:delete() 方法会把持久化对象或游离对象的 OID 设置为 null,使它们变为临时对象。这样程序就可以重复利用这些对象了