返回介绍

11.2.2 编写基于 JPA 的 Repository

发布于 2024-08-17 00:45:49 字数 2872 浏览 0 评论 0 收藏 0

正如Spring对其他持久化方案的集成一样,Spring对JPA集成也提供了JpaTemplate模板以及对应的支持类JpaDaoSupport。但是,为了实现更纯粹的JPA方式,基于模板的JPA已经被弃用了。这与我们在11.1.2小节使用的Hibernate上下文Session是很类似的。

鉴于纯粹的JPA方式远胜于基于模板的JPA,所以在本节中我们将会重点关注如何构建不依赖Spring的JPA Repository。如下程序清单中的JpaSpitterRepository展现了如何开发不使用Spring JpaTemplate的JPA Repository。

程序清单11.2 不使用Spring模板的纯JPA Repository

程序清单11.2中,需要注意的是EntityManagerFactory属性,它使用了@PersistenceUnit注解,因此,Spring会将EntityManagerFactory注入到Repository之中。有了EntityManagerFactory之后,JpaSpitterRepository的方法就能使用它来创建EntityManager了,然后EntityManager可以针对数据库执行操作。

在JpaSpitterRepository中,唯一的问题在于每个方法都会调用createEntityManager()。除了引入易出错的重复代码以外,这还意味着每次调用Repository的方法时,都会创建一个新的EntityManager。这种复杂性源于事务。如果我们能够预先准备好EntityManager,那会不会更加方便呢?

这里的问题在于EntityManager并不是线程安全的,一般来讲并不适合注入到像Repository这样共享的单例bean中。但是,这并不意味着我们没有办法要求注入EntityManager。如下的程序清单展现了如何借助@PersistentContext注解为JpaSpitterRepository设置EntityManager。

程序清单11.3 将EntityManager的代理注入到Repository之中

在这个新版本的JpaSpitterRepository中,直接为其设置了EntityManager,这样的话,在每个方法中就没有必要再通过EntityManagerFactory创建EntityManager了。尽管这种方式非常便利,但是你可能会担心注入的EntityManager会有线程安全性的问题。

这里的真相是@PersistenceContext并不会真正注入EntityManager——至少,精确来讲不是这样的。它没有将真正的EntityManager设置给Repository,而是给了它一个EntityManager的代理。真正的EntityManager是与当前事务相关联的那一个,如果不存在这样的EntityManager的话,就会创建一个新的。这样的话,我们就能始终以线程安全的方式使用实体管理器。

另外,还需要了解@PersistenceUnit和@PersistenceContext并不是Spring的注解,它们是由JPA规范提供的。为了让Spring理解这些注解,并注入EntityManager Factory或EntityManager,我们必须要配置Spring的Persistence-AnnotationBeanPostProcessor。如果你已经使用了<context:annotation-config>或<context:component-scan>,那么你就不必再担心了,因为这些配置元素会自动注册PersistenceAnnotationBeanPostProcessor bean。否则的话,我们需要显式地注册这个bean:

你可能也注意到了JpaSpitterRepository使用了@Repository和@Transactional注解。@Transactional表明这个Repository中的持久化方法是在事务上下文中执行的。

对于@Repository注解,它的作用与开发Hibernate上下文Session版本的Repository时是一致的。由于没有使用模板类来处理异常,所以我们需要为Repository添加@Repository注解,这样PersistenceExceptionTranslationPostProcessor就会知道要将这个bean产生的异常转换成Spring的统一数据访问异常。

既然提到了PersistenceExceptionTranslationPostProcessor,要记住的是我们需要将其作为一个bean装配到Spring中,就像我们在Hibernate样例中所做的那样:

提醒一下,不管对于JPA还是Hibernate,异常转换都不是强制要求的。如果你希望在Repository中抛出特定的JPA或Hibernate异常,只需将PersistenceException-TranslationPostProcessor省略掉即可,这样原来的异常就会正常地处理。但是,如果使用了Spring的异常转换,你会将所有的数据访问异常置于Spring的体系之下,这样以后切换持久化机制的话会更容易。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文