对象(实体的实例)对一个特定的Session来说,要么是一个瞬时(transient)对象,要么是持久化(persistent)对象。刚刚创建的对象当然是瞬时的(注:后文中transient object也称为临时对象)。session则提供了把瞬时实例保存(持久化)的服务:
DomesticCat fritz = new DomesticCat(); fritz.setColor(Color.GINGER); fritz.setSex('M'); fritz.setName("Fritz"); Long generatedId = (Long) sess.save(fritz);
DomesticCat pk = new DomesticCat(); pk.setColor(Color.TABBY); pk.setSex('F'); pk.setName("PK"); pk.setKittens( new HashSet() ); pk.addKitten(fritz); sess.save( pk, new Long(1234) );
单参数的save()方法为fritz生成了一个惟一标识符,并赋给这个对象。双参数的形式则使用给定的标识符保存pk。我们一般不鼓励使用双参数的形式,因为这可能会(隐含)使主键赋予业务含义。它有用的时候是在一些特殊场合下,比如使用Hibernate来持久化一个BMP实体bean.
关联的对象可以用你喜欢的任何顺序持久化,除非有外键字段具有NOT NULL的约束。决不会有外键约束冲突的危险。然而,如果在save()对象的时候用错了顺序,会触犯NOT NULL约束。
如果你已知某个持久化实例的标识符,Session的load()方法让你取出它。第一种形式使用一个类对象作为参数,会把状态装载到另一个新创建的对象中去。第二个版本允许你给出一个实例,会在其中装载状态。把实例作为参数的形式在你准备把Hibernate和BMP实体bean一起使用的时候特别有用,它就是为此设计的。你也可以发现其他的用途(比如自己实现实例池等等)。
Cat fritz = (Cat) sess.load(Cat.class, generatedId);
// you need to wrap primitive identifiers long pkId = 1234; DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );
Cat cat = new DomesticCat(); // load pk's state into cat sess.load( cat, new Long(pkId) ); Set kittens = cat.getKittens();
请注意如果没有匹配的数据库记录,load()方法可能抛出无法恢复的exception。如果类是通过代理映射的,load()方法返回一个对象,这是一个未初始化的代理,并且直到你调用该对象的某方法时才会去访问数据库。这种行为方式在你喜欢创建一个指向某对象的关联,又不想真的从数据库中装载它的时候特别有用。
如果你不确定是否有匹配的行存在,你应该使用get()方法,它会立刻访问数据库,如果没有对应的行,返回null。
Cat cat = (Cat) sess.get(Cat.class, id); if (cat==null) { cat = new Cat(); sess.save(cat, id); } return cat;
你可以用SQLSELECT ... FOR UPDATE装载对象。下一节有关于Hibernate LockMode的讨论。
Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);
注意,任何关联的实例或者包含的集合都不会被做为FOR UPDATE返回。
任何时候都可以使用refresh()方法重新装载对象和它的集合。如果你使用数据库触发器更改了对象的某些属性,这就很有用。
sess.save(cat); sess.flush(); //force the SQL INSERT sess.refresh(cat); //re-read the state (after the trigger executes)