Spring Data JPA是在Spring JPA的基础上,对持久层做了简化。用户只需声明持久层的接口,不需要实现该接口。Spring Data JPA内部会根据不同的策略、通过不同的方法创建Query操作数据库。
Spring 将 EntityManager 的创建与销毁、事务管理等代码抽取出来,并由其统一管理,开发者不需要关心这些,业务方法中只剩下操作领域对象的代码,事务管理和 EntityManager创建、销毁的代码都不再需要开发者关心了。
Spring Data JPA使用方法
Spring Data JPA 简化持久层开发大致需要如下几个步骤。
(1) 引入依赖的jar文件
以Maven方式为例,引入jar包:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.7.0.RELEASE</version>
</dependency>
(2) 在Spring的配置文件中添加配置
在配置文件中设置实体类所在的包,定义entityManagerFactory、transactionManager等信息。
Spring会在base-package中定义的package和其子package中搜寻继承了Repository的接口。
<beans
...
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
...
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd ">
<!-- 其他... -->
<!-- JPA实体管理工厂的配置 -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="com.mj.dsl.jpa" /><!--待扫描的实体类包,不再需要persistence.xml了 -->
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- Spring Data JPA配置 -->
<jpa:repositories base-package="com.eric.test.jpa" />
<!--指定实现JPA的适配器 -->
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<!-- <property name="databasePlatform" value="org.hibernate.dialect.DerbyDialect" /> -->
</bean>
<!-- JPA事务配置 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" scope="prototype">
<property name="transactionManager" ref="transactionManager" />
</bean>
<!-- 使用annotation定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />
<!-- 其他... -->
</beans>
(3) 声明持久层接口
该接口继承Repository <T,ID>或其子接口,T是领域实体,ID是领域实体的主键类型。例:
public interface UserRepository extends Repository<User, Long> {……}
(4) 在持久层的接口中声明需要的业务方法
Spring Data JPA将会根据指定的策略为该方法生成实现代码。用户不需要实现该接口。例:
List<User> findByLastname(String lastname);
Repository 接口说明
Repository是SpringData的核心接口,它并不提供任何方法,用户需要自己定义需要的方法。(1) 继承Repository接口的两种方法
①直接继承
public interface UserDao extends Repository<User, Long> { …… }
②使用@RepositoryDefinition注解
@RepositoryDefinition(domainClass = User.class, idClass = Long.class)
public interface UserDao { …… }
(2) 其他Repository接口
CrudRepository(Spring Data提供) | 继承Repository,提供增删改查方法,可以直接调用。 |
PagingAndSortingRepository(Spring Data提供) | 继承CrudRepository,增加了分页查询和排序两个方法 |
JpaRepository(Spring Data JPA提供) | 继承PagingAndSortingRepository,是针对JPA技术的接口,提供flush(),saveAndFlush(),deleteInBatch()等方法 |
创建Query
Spring Data JPA会通过解析用户在持久层接口中定义的方法名来生成相应的query语句。解析时能被识别的keyword和包含这些keyword的方法会被解析成什么样的Query,如下所示:
And --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);
Or --- 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);
Between --- 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min);
LessThan --- 等价于 SQL 中的 "<",比如 findBySalaryLessThan(int max);
GreaterThan --- 等价于 SQL 中的">",比如 findBySalaryGreaterThan(int min);
IsNull --- 等价于 SQL 中的 "is null",比如 findByUsernameIsNull();
IsNotNull --- 等价于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();
NotNull --- 与 IsNotNull 等价;
Like --- 等价于 SQL 中的 "like",比如 findByUsernameLike(String user);
NotLike --- 等价于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);
OrderBy --- 等价于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);
Not --- 等价于 SQL 中的 "! =",比如 findByUsernameNot(String user);
In --- 等价于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
NotIn --- 等价于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
LocalContainerEntityManagerFactoryBean与LocalEntityManagerFactoryBean的区别
LocalEntityManagerFactoryBean
程序管理型:实体管理器是在程序直接向实体管理器工厂请求一个实体管理器时创建的。在这种情况下,程序负责打开或关闭实体管理器,并且在事务中控制管理器。这种类型最适合不运行于Java EE容器的独立程序。
LocalContainerEntityManagerFactoryBean
容器管理型:实体管理器由Java EE容器创建和管理。这种情况下,程序根本不与实体管理器工厂进行交互,实体管理器是通过注入或利用JNDI直接获得的,容器负责配置实体管理器工厂。这种类型最适合希望不考虑persistence.xml中的特殊性而在JPA配置之上维持某种控制的Java EE容器。
参考资料:
[1] 了解Spring Data JPA
[2] SpringData JPA详解