初步了解Hibernate与对象共事

开发 后端
Hibernate是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。

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)的。

  1. DomesticCat fritz = new DomesticCat();  
  2. fritz.setColor(Color.GINGER);  
  3. fritz.setSex('M');  
  4. fritz.setName("Fritz");  
  5. 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()方法。

  1. DomesticCat pk = new DomesticCat();  
  2. pk.setColor(Color.TABBY);  
  3. pk.setSex('F');  
  4. pk.setName("PK");  
  5. pk.setKittens( new HashSet() );  
  6. pk.addKitten(fritz);  
  7. 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)。

  1. Cat fritz = (Cat) sess.load(Cat.class, generatedId);  
  2. // you need to wrap primitive identifiers  
  3. long pkId = 1234;  
  4. DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );  

此外, 你可以把数据(state)加载到指定的对象实例上(覆盖掉该实例原来的数据)。

  1. Cat cat = new DomesticCat();  
  2. // load pk's state into cat  
  3. sess.load( cat, new Long(pkId) );  
  4. Set kittens = cat.getKittens(); 

请注意如果没有匹配的数据库记录,load()方法可能抛出无法恢复的异常(unrecoverable exception)。 如果类的映射使用了代理(proxy),load()方法会返回一个未初始化的代理,直到你调用该代理的某方法时才会去访问数据库。 若你希望在某对象中创建一个指向另一个对象的关联,又不想在从数据库中装载该对象时同时装载相关联的那个对象,那么这种操作方式就用得上的了。 如果为相应类映射关系设置了batch-size, 那么使用这种操作方式允许多个对象被一批装载(因为返回的是代理,无需从数据库中抓取所有对象的数据)。

如果你不确定是否有匹配的行存在,应该使用get()方法,它会立刻访问数据库,如果没有对应的行,会返回null。

  1. Cat cat = (Cat) sess.get(Cat.class, id);  
  2. if (cat==null) {  
  3.     cat = new Cat();  
  4.     sess.save(cat, id);  
  5. }  
  6. return cat; 

你甚至可以选用某个LockMode,用SQL的SELECT ... FOR UPDATE装载对象。 请查阅API文档以获取更多信息。

  1. Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE); 

注意,任何关联的对象或者包含的集合都不会被以FOR UPDATE方式返回, 除非你指定了lock或者all作为关联(association)的级联风格(cascade style)。

任何时候都可以使用refresh()方法强迫装载对象和它的集合。如果你使用数据库触发器功能来处理对象的某些属性,这个方法就很有用了。

  1. sess.save(cat);  
  2. sess.flush(); //force the SQL INSERT  
  3. sess.refresh(cat); //re-read the state (after the trigger executes) 

此处通常会出现一个重要问题: Hibernate会从数据库中装载多少东西?会执行多少条相应的SQLSELECT语句? 这取决于抓取策略(fetching strategy),这里我们不再做以解释。

【编辑推荐】

  1. 简述Hibernate中加载并存储对象
  2. Hibernate传播性持久化攻略
  3. 深入了解Hibernate自动状态检测
  4. 教你如何在Hibernate中实例化集合和代理
  5. Hinerbate单端关联代理颇析
责任编辑:仲衡 来源: redsaga
相关推荐

2022-12-22 13:18:54

深度学习框架

2019-11-05 10:18:04

RPM包RPMLinux

2016-08-03 15:32:50

GitLinux开源

2009-11-11 16:34:45

Visual Stud

2023-01-06 19:19:16

TensorFlow

2012-02-08 14:24:35

HibernateJava

2012-08-30 14:17:42

IBMdw

2009-09-23 10:14:10

Hibernate使用

2009-09-29 10:46:58

Hibernate领域

2009-09-25 13:14:58

Hibernate C

2010-09-09 16:21:32

TCP IP网络协议

2021-09-02 15:29:42

鸿蒙HarmonyOS应用

2024-02-04 09:05:52

持久态对象数据库

2009-09-23 13:26:10

Hibernate对象

2009-09-22 11:27:41

模型对象Hibernate

2023-11-02 07:55:31

Python对象编程

2009-09-24 16:22:50

Hibernate自动

2009-10-30 09:45:55

VB.NET Web

2011-02-18 09:01:26

Microsoft V

2016-11-14 17:36:57

Angular 2应用程序端对端
点赞
收藏

51CTO技术栈公众号