JDBC可以很好的完成数据持久化工作,但随着应用变动复杂,持久化的需求也变的多样,我们需要对象的属性映射到数据库的列上,并且自动生成语句和查询,此外还需要一些更复杂的特性,如:延迟加载、预先抓取、级联等。
一些框架提供了这样的服务,这些服务就是对象/关系映射(ORM)。在持久层使用ORM框架可以节省许多代码与开发时间。Spring对多个持久化框架都提供了支持,Spring对ORM框架的支持提供了与这些框架的集成点以及一些附加的服务:
支持集成Spring声明式事务
透明的异常处理
线程安全的、轻量级的模板类
DAO支持类
资源管理
Spring与Java持久化API
Java持久化API(JPA)是java持久化标准。在Spring中使用JPA的第一步是在Spring应用上下文中将实体管理器工厂按照bean的形式来进行配置。
配置实体管理器工厂
基于JPA的应用程序需要使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型实体管理器:
应用程序管理类型:当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。
容器管理类型:实体管理器有JavaEE创建和管理。应用程序不与实体管理器工厂打交道。实体管理器直接通过注入或JNDI来获取。容器负责配置实体管理器工厂。
以上两种实体管理器实现了同一个EntityManager接口。区别不在EntityManager本身,而在于EntityManager的创建和管理方式。两种实体管理工厂分别由对应Spring工厂Bean创建:
LocalEntityManagerFactoryBean生成应用程序管理类型的EntityManagerFactory
LocalContainerEntityManagerFactoryBean生成容器管理类型的EntityManagerFactory
选择应用程序管理类型还是容器管理类型的EntityManagerFactory对于基于Spring的应用程序来说完全透明。
配置应用程序管理类型的JPA
应用程序管理类型的实体管理工厂绝大部分配置信息在persistence.xml的配置文件中,这个文件必须位于类路径下的META-INF目录下。Persistence.xml用于定义一个或多个持久化单元。持久化单元是同一个数据源下的一个或多个持久化类。在persistence.xml文件包含大量的配置信息,所以Spring中只需使用@Bean注解在spring中声明LocalEntityManagerFactoryBean。
使用容器管理类型的JPA
容器管理的JPA才去了一个不同的方式。当运行在容器是,可以使用容器提供的信息来生产EntityManagerFactory。可以将数据源信息配置在Spring应用上下文中,而不是persistence.xml中。
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter){
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
return factoryBean;
}
这里使用Spring配置的数据源来设置dataSource属性,任何javax.sql.DataSource的实现都可以。
JpaVenderAdapter属性用于指明所使用的是哪一个厂商的JPA实现,以下是Spring提供的JPA实现:
EclipseLinkJpaVendorAdapter
HibernateJpaVendorAdapter
OpenJpaVendorAdapter
TopLinkJpaVendorAdapter(废弃)
从JNDI获取实体管理器工厂
如果Spring应用程序部署在应用服务器中,EntityManagerFactory可能已经创建好并位于JNDI中等待查询使用,这种情况可以使用Spring jee命名空间下的<jee:jndi-lookup>元素来获取对EntityManagerFactory的引用。
编写基于JPA的Repository
在Repository中,使用@persistenceUnit注解将EntityManagerFactory注入到Repository中,有了EntityManagerFactory之后,jpa的Repository的方法就能使用它来创建EntityManager,然后EntityManager可以针对数据库执行操作。
EntityManager并不是线程安全的,一般来将不适合注入到想Repository这样共享单例bean中,可以借助@PersistentContext注解为Jpa的Repository设置EntityManager。@PersistentContext并不会真正注入EntityManager。它没有将真正的EntityManager设置给Repository,而是给了一个EntityManager的代理。真正的EntityManager是与当前事务相关联的那个,如果不存在这样的EntityManager的话,就会新创建一个,这样就能始终以线程安全的方式使用实体管理器。
@PersistenceUnit和@PersistenceContext并不是Spring的注解,是由JPA规范提供的。为了让Spring理解这些注解,必须配置Spring的PersistenceAnnotationBeanPostProcessor。
借助Spring Data实现自动化JPA Repository
为了通过SpringData创建Repository的实现,需要在Spring的配置中添加<jpa:repositories>元素。<jpa:repositories>元素需要指定一个要进行扫描的base-package。<jpa:repositories>会扫描他的基础包来查找扩展自SpringData JPA Repository接口的所有接口。如果发现了扩展自Repository的接口,会自动生成这个接口的实现。如果要使用Java配置的话,就不需要<jpa:repositories>元素,而是要在Java配置类上添加@EnableJpaRepositories注解。当SpringData发现JpaRepository的接口或子接口后,就会创建该Repository的实现类,其中包含了继承自JpaRepository、PagingAndSortingRepository和CrudRepository的18个方法。
当创建Repository实现时,SpringData会检查Repository接口的所有方法,解析方法的名称,并基于被持久化的对象来视图推测方法的目的,本质上,Spring Data定义了一组小型的领域特定语言,持久化的细节都是通过Repository方法的签名来描述的。
readUserByFirstnameOrLastnameOrderByLastname();
read:查询动词
User:主题
FirstnameOrLastnameOrderByLastname:断言
具体细节另写吧。SpringData是可以单写一章的。





