Hibernate使用技巧

很多程序员认为一旦使用类似Hibernate这样的对象关系映射工具(object-relational mapping tool)就不用去担心持久化问题了,神奇的Hibernate会处理好所有的事情。但是事实上可能刚好相反。正因为使用Hibernate这样的技术,程序员才更应该清楚的明白域对象(domain object)以及如何获取这些对象。这方面的错误同样会导致数据库发生异常。使用Hibernate使得程序员可以忽略对象和关系结构之间的不一致,但这也意味着,如果你要求它去做些傻事,它也会毫不犹豫的去做。比如可怕的n+1错误。请记住,Hibernate可以做很多事情,但不能帮你写代码。

        这篇文章总结了我使用Hibernate的一些经验,以及在使用过程中学习到的一些技术技巧和知识。

 

如何定义实体

        持久化策略(或许也是整个应用)中最重要的就是实体定义。所有的对象都是从核心对象集合中繁衍而来的,因此正确的定义实体是非常重要的。下面是构建Hibernate/JPA实体方面我的一些建议。

1.    创建一个新类,实现java.io.Serializable接口(并且显式定义serialVersionUID这个变量)。

2.    增加类变量@Id Serializable id 和 @Version Date lastUpdated。这两个变量分别是数据库主键(primary key)和实现乐观锁(optimistic locking)的版本号标记。

3.     增加任何需要的属性。

4.     写一个缺省的构造器。所有的类型的变量都应该在这里初始化,包括集合(Collection),列表(List),集合(Set)等等

5.    为所有的属性创建getter和setter方法:

        a)   应该为id和lastUpdated创建public getter方法,但是不要创建setter方法。

        b)   应该为Collection、List、Set等类型的变量创建public getter方法,但不要创建setter方法。Public getter方法最好返回一个不能修改的list。

6.    增加JPA/Hibernate注解。给getter方法增加注解。(或者我可以直接在变量上增加注解吗?)

        a)    添加Hibernate合法性注解,例如@NotNull、@Length、@Range等。

        b)    即使名字相同,也应该添加@Column(name=xxx)注解。因为你肯定不想忘记数据所依赖的最初的列名是什么。

        c)     在定义关系的实体中增加@OneToOne、@OneToMany、 @ManyToOne 或者@ManyToMany注解

7.     如果使用关系映射,确保其是双向的(bidirectional)。简单起见,我会创建工具方法(utility method)来处理关系映射的一端:集合(Collection)类型的属性有工具方法 addXXX和removeXXX。(或许对应的关系映射的另一端类的setter方法应该设为受保护的(protected),然后从工具方法中调用)

8.     实现equal和hashcode方法。非常重要!

        a)    这样会使用id的方式来进行比较,从而减少比较次数。

        b)    使用Hibernate.isInitialized()方法来判断是否存在代理实例或者代理实例是否被初始化了。

        c)     写equal和hashcode方法时,不是所有的成员(field)都要用上,而是应该使用那些真正可以区分不同对象的成员。

9.     用jakarta commons 的ToStringBuilder 构建自己的toString()方法,这样可以让调试容易些。

10.   给Spring的配置文件增加一个映射元素。

 

get()方法和load()方法分析

        Session#get() 和 Session#load()一个很重要的区别,就是对于数据库读取效率的影响不同。get()方法从数据库返回一个对象实例,而load()方法则返回一个对象代理(proxy),当实际使用时才从当前session中返回对象实例。当使用load()时,是没有实际访问数据库的。这个时候只是通过对象的属性(非id)进行初始化工作。当进行实例赋值的时候使用load(),也就意味着并不是想立即获得对象的数据,而是得到一个标识符(identifier)从而建立起关联。还有一点很重要,就是如果数据库中不存在对应的行的时候使用load()方法,那么程序会抛出ObjectNotFoundException异常。

单元测试断言(Unit Testing  Assertion)

        单元测试时使用Session#flush() 和 Session#evict()分别向数据库写数据以及清除一级缓存(内存中),从而使得接下来的程序能够验证修改是否被写入了数据库。evict()方法保证下次再去读同一个实例时,拿到的不是一级缓存中的对象而是从数据库里拿出来的最新的对象。

        Session#close()用来关闭当前session并且检查延迟加载(lazy association)的状态,如果没有拿到期望的数据,那么就会抛出一个LazyInitializationException异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hibernate使用技巧汇总<br><br>1.两种配置文件: <br> A.hibernate.cfg.xml 和 B.hibernate.properties <br> A中可含映射文件的配置,而B中hard codes加映射文件。 <br> A。Configuration config=new Configuration().config(); <br> B. Configuration config=new Configuration(); <br> config.addClass(TUser.class); <br><br>2.你不必一定用hibernate.cfg.xml或hibernate.properties这两文件名, <br> 你也不一定非得把配置文件放在Classes下, <br> File file=new File("c:\\sample\\myhibernate.xml"); <br> Configuration config=new Configuration().config(file); <br>3. session.Flush() <br> 强制数据库立即同步,当用事务时,不必用flush,事务提交自动调用flush <br> 在session关闭时也会调用flush <br><br>4. Hibernate总是使用对象类型作为字段类型 <br>5. XDoclet专门建立了hibernate doclet,就是在java代码上加上一些 <br> java docTag,后来再让XDoclet分析该java代码,生成映射文件; <br>6.HQL子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分。 <br>7.关系: <br> Constrained : 约束,表明主控表的主键上是否存在一个外键(foreigh key) <br> 对其进行约束。 <br> property-ref:关联类中用于与主控类相关联的属性名,默认为关联类的主键属性名 <br> 单向一对多需在一方配置,双向一对多需在双方进行配置 <br>8.lazy=false:被动方的记录由hibernate负责记取,之后存放在主控方指定的 <br> Collection类型属性中 <br><br>...............<br><br><br>...............<br><br><br>27.Spring的参数化事务管理功能相当强大,笔者建议在基于Spring Framework的应用 <br>开发中,尽量使用容器管理事务,以获得数据逻辑代码的最佳可读性。 <br> <br>public class UserDAO extends HibernateDaoSupport implements IUserDAO <br>{ <br>public void insertUser(User user) { <br>getHibernateTemplate().saveOrUpdate(user); <br>} <br>} <br><br> 上面的UserDAO实现了自定义的IUserDAO接口,并扩展了抽象类: <br>HibernateDaoSupport <br>HibernateSupport实现了HibernateTemplate和SessionFactory实例的关联。 <br>HibernateTemplate对Hibernate Session操作进行了封装,而 <br>HibernateTemplate.execute方法则是一封装机制的核心 <br> *在spring的配置文件里,移植了整个hibernate.cfg.xml的内容。<br>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值