本篇内容介绍了“Hibernate与对象是怎么共事的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Hibernate是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。
也就是说,相对于常见的JDBC/SQL持久层方案中需要管理SQL语句,Hibernate采用了更自然的面向对象的视角来持久化Java应用中的数据。
换句话说,使用Hibernate的开发者应该总是关注对象的状态(state),不必考虑SQL语句的执行。这部分细节已经由Hibernate掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。
1. Hibernate对象状态(object states)
Hibernate定义并支持下列对象状态(state):
瞬时(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)。
接下来我们来细致的讨论下状态(states)及状态间的转换(state transitions)(以及触发状态转换的Hibernate方法)。
2. 使对象持久化
Hibernate认为持久化类(persistent class)新实例化的对象是瞬时(Transient)的。我们可将瞬时(Transient)对象与session关联而变为持久(Persistent)的。
DomesticCat fritz = new DomesticCat(); fritz.setColor(Color.GINGER); fritz.setSex('M'); fritz.setName("Fritz"); Long generatedId = (Long) sess.save(fritz);
如果Cat的持久化标识(identifier)是generated类型的,那么该标识(identifier)会自动在save()被调用时产生并分配给cat。如果Cat的持久化标识(identifier)是assigned类型的,或是一个复合主键(composite key),那么该标识(identifier)应当在调用save()之前手动赋予给cat。 你也可以按照EJB3 early draft中定义的语义,使用persist()替代save()。
此外,你可以用一个重载版本的save()方法。
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) );
如果你持久化的对象有关联的对象(associated objects)(例如上例中的kittens集合)那么对这些对象(译注:pk和kittens)进行持久化的顺序是任意的(也就是说可以先对kittens进行持久化也可以先对pk进行持久化),除非你在外键列上有NOT NULL约束。 Hibernate不会违反外键约束,但是如果你用错误的顺序持久化对象(译注:在pk持久之前持久kitten),那么可能会违反NOT NULL约束。
通常你不会为这些细节烦心,因为你很可能会使用Hibernate的传播性持久化(transitive persistence)功能自动保存相关联那些对象。 这样连违反NOT NULL约束情况都不会出现了Hibernate会管好所有的事情。传播性持久化(transitive persistence)将在本章稍后讨论。
3. 装载对象
如果你知道某个实例的持久化标识(identifier),你就可以使用Session的load()方法 来获取它。 load()的另一个参数是指定类的.class对象。 本方法会创建指定类的持久化实例,并从数据库加载其数据(state)。
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) );
此外, 你可以把数据(state)加载到指定的对象实例上(覆盖掉该实例原来的数据)。
Cat cat = new DomesticCat(); // load pk's state into cat sess.load( cat, new Long(pkId) ); Set kittens = cat.getKittens();
请注意如果没有匹配的数据库记录,load()方法可能抛出无法恢复的异常(unrecoverable exception)。 如果类的映射使用了代理(proxy),load()方法会返回一个未初始化的代理,直到你调用该代理的某方法时才会去访问数据库。 若你希望在某对象中创建一个指向另一个对象的关联,又不想在从数据库中装载该对象时同时装载相关联的那个对象,那么这种操作方式就用得上的了。 如果为相应类映射关系设置了batch-size, 那么使用这种操作方式允许多个对象被一批装载(因为返回的是代理,无需从数据库中抓取所有对象的数据)。
如果你不确定是否有匹配的行存在,应该使用get()方法,它会立刻访问数据库,如果没有对应的行,会返回null。
Cat cat = (Cat) sess.get(Cat.class, id); if (cat==null) { cat = new Cat(); sess.save(cat, id); } return cat;
你甚至可以选用某个LockMode,用SQL的SELECT ... FOR UPDATE装载对象。 请查阅API文档以获取更多信息。
Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);
注意,任何关联的对象或者包含的集合都不会被以FOR UPDATE方式返回, 除非你指定了lock或者all作为关联(association)的级联风格(cascade style)。
任何时候都可以使用refresh()方法强迫装载对象和它的集合。如果你使用数据库触发器功能来处理对象的某些属性,这个方法就很有用了。
sess.save(cat); sess.flush(); //force the SQL INSERT sess.refresh(cat); //re-read the state (after the trigger executes)
“Hibernate与对象是怎么共事的”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。