JPA与Hibernate的那些事

使用JPA而不是Hibernate,我们将失去什么?

JPA相对于Hibernate,丢失了很多宝贵的东西,不支持面向对象的Criterion查询,使得我们很多基本的功能无法简单实现。如,通过 对象的属性值实现查询,我们将不得不去写JPQL,通过对字符串的操作来实现功能。一个很大的问题是,对字符串的操作是比较不安全的,如 removeOrderBy的方式实现里,我们就通过找到"order by",然后去掉后面部分来实现;但是,如果order和by之间再多一个空格,就会出现bug。当然,你也可以写一些严格的方法来避免这种问 题,hibernate的Criterion实现里也一定是这样实现的,但这样就增加了我们开发的复杂度,重复了hibernate已经实现了的工作。

JPA为什么不提供Criterion查询?

JPA是一种规范,是为了统一ORM当前混乱的局面而产生的。但是当前除了hibernate,其他ORM框架是没有提供类似于Criterion的查询方式的,所以规范里不能提出这种Criterion这种标准的,那样的话会使得大部分ORM框架无法实现JPA规范。

 

 

JPA2.0规范将支持Criterion查询。

 

JPA不支持类似saveOrUpdate的方法

@org.hibernate.annotations.Index

hibernate为字段定义索引,这样通过工具读取映射文件(或annotation标注的映射元数据)生成ddl文件时,就可以自动为该字段创建索引。

在使用JPA时,我们可以同时定义这个索引,它虽然不被JPA的其他实现识别,但不会影响(JPA使用其他实现时)程序的正常运行。

如:

	@org.hibernate.annotations.Index(name = "name"

)
	@javax.persistence.Column(length = 50, nullable = false

)
	public

 String

 getName() {
		return

 name;
	}

这样,在使用hibernate-tools生成ddl时,会自动为name字段创建一个名称为"name"的索引。

JPA不支持有序集合的映射

在使用hibernate时,我们经常会使用List来映射一些有序集合。

一个典型的应用场景是菜单,由于菜单是有序的,我们会为每个菜单维护一个类似于position的字段,来区分同一个菜单下子菜单的排序。

使用hibernate时,我们可以通过将children这个属性映射为List,并指定其排序字段来实现:

	@OneToMany(mappedBy = "parent"

)
	@org.hibernate.annotations.IndexColumn(name = "position"

)
	public

 List<Menu> getChildren() {
		return

 children;
	}

这样,我们就不用自己来维护菜单的排序字段position了,要实现其顺序,我们只需要更改菜单在children这个集合的先后顺序就OK了。

JPA标准中还不支持这种映射,目前我们使用hibernate的实现,这样映射是没有问题的,但是我们应该记住,这样是不符合JPA标准的,切换到另外一种实现这段代码是存在问题的。

Hibernate.initialize(Object o)

在dao里,我们可能需要手动去加载一个延迟加载的对象或属性或集合,这在hibernate里可以调用 Hibernate.initialize(Object o)方法来实现,而在JPA里好像还不能实现这个功能,我们目前的替代方案是,在同一个事务里手动去调用要加载对象的一个get方法,来触发这个加载过 程。


JPA2.0将支持多种集合的映射(应该支持List映射,没有深入了解规范内容)。

JPA1.0不支持二级缓存!!!

JPA1.0不支持二级缓存,表现在:

  • 规范没有对二级缓存的支持

不过还是可以使用JPA具体实现对二级缓存的支持的

  • JPA1.0规范的接口中没有对二级缓存的支持

为了解释这个问题,首先我们需要了解的是hibernate中Query接口对二级缓存的支持。

要知道,hibernate的Query接口提供的一些方法,如list,是不会去访问二级缓存的,而是直接生成sql去访问数据库。如果我们一味调用list方法,那么二级缓存的开启将形同虚设,并且会降低系统性能(因为二级缓存基本是个累赘)。
为了有效hit二级缓存,hibernate的Query接口提供了iterator方法,其实现是,先生成一条sql去数据库查询所有满足条件的实体的 id,然后根据得到的id去二级缓存查找对应的对象;如果没有找到对应的对象,则去数据库根据id去加载这个对象,并将加载到的对象缓存起来。(这样产生 一个问题,iterator在第一次调用时无法避免n+1次查询问题)

但是,JPA1.0规范中的Query接口并没有提供类似于iterator的接口,而只提供了类似于list的接口getResultList。这导致我们使用JPA1.0的接口时,将无法有效使用二级缓存。也就是说,我们只要调用Query.getResultList()接口去查询数据(这也是我们执行jpql的唯一途径),它都会去数据库进行查询,而不会去访问二级缓存。
目前要解决这个问题,只能在dao的接口里直接使用hibernate提供的Query接口,而不是JPA的接口。而这样做无疑不是我们使用JPA的初衷。

  • JPA1.0不支持查询缓存

在hibernate里,查询缓存的概念在于,使用一条hql进行查询后,可以将查询结果缓存起来,下次使用相同的hql进行查询时,可以重复使用查询结果。(目前只了解其概念,没有实践过)
JPA1.0不支持查询缓存。
不过据了解,hibernate的查询缓存并不被推荐使用,推荐大量使用的是二级缓存。所以,这个也无伤大雅。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值