Spring Data JPA快速入门
Spring Data Jpa
概述
简介
Spring Data JPA 是一套基于ORM(对象关系映射)框架,JPA规范封装的一套JPA应用框架.开发者可以用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常用功能,切易于扩展.
使用Spring Data JPA 可以极大的提高开发效率.
常见的ORM框架有Hibernate,Mybatis,topLink等等.
Spring Data JPA的内容
Spring Data JPA提供的编程接口:
1.Repository:最顶层的接口,是一个空接口.目的是为了统一索引的Repository的类型,且能让组件扫描的时候自动识别.
2:CrudRepository :是Repository的子接口,提供CRUD的功能
3:PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能
4:JpaRepository:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等。
5:JpaSpecificationExecutor:用来做复杂查询的接口
6:Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可
Jpa Specification Executor接口与左边的接口没有直接继承关系,它是作为一个辅助接口使用的.
快速入门
搭建”用户管理”项目,具体分为以下步骤:
1. 建立工程
2. 导入所有配置
3. 配置与编码
建立工程
准备开发工具
开发工具Eclipse,MySql数据库,数据库管理工具Navicat
创建数据库及表格
建立数据库: user_manage
建立数据表:user
在Eclipse中建立java工程
创建工程结构
应用重要的几个层次及调用关系图
中间的三个层次是项目的核心层次,是我们构建项目mvc的核心,我们基于这些层次确定包结构:
***.repository ---- 存放自定义的数据操作接口,相当于dao
***.service ---- 存放服务层的接口和实现
***.controller ---- 存放控制器类
***.model ---- 存放实体类
***.exception ---- 存放异常类
***.test ---- 存放测试类
引入所需的jar包
本项目使用maven创建工程,pom.xml中配置jar包的依赖:
<!-- spring相关的依赖,必须统一版本号,防止版本冲突 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!-- spring Data JPA的依赖 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.10.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.6.10.Final</version>
</dependency>
<!-- commons依赖 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<classifier>jdk15</classifier>
<version>2.3</version>
</dependency>
<!-- 数据库相关依赖 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.5</version>
</dependency>
<!-- 日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.5.8</version>
</dependency>
配置与编码
创建配置: application.xml ---- Spring上下文
Persistence.xml ---- 管理持久化
Persistence.xml :
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="userPU" transaction-type="RESOURCE_LOCAL">
<provider >org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<!-- 配置数据库连接信息 -->
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/user_manage"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="root"/>
<!-- 配置Hibernate的方言 -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<!-- hibernate日志输出配置 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<!-- 根据java模型生成数据库表结构的策略 -->
<property name="hibernate.hbm2ddl.auto" value="update"/>
<!-- 命名策略 : 驼峰命名法-->
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"></property>
</properties>
</persistence-unit>
</persistence>
Application.xml :
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"
default-lazy-init="true">
<!--第一步-->
<!--定义服务层代码存放的包扫描路径-->
<context:component-scan base-package="cn.wxdl.usermanage.service" />
<!--第二步-->
<!--定义实体的工厂bean-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="userPU" />
<property name="persistenceXmlLocation" value="classpath:persistence1.xml"></property>
</bean>
<!--第三步-->
<!--定义事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--第四步-->
<!--定义repository接口的存放目录-->
<!--定义接口实现的后缀,通常用Impl-->
<!--定义实体工厂的引用-->
<!--定义事务管理器的引用-->
<jpa:repositories base-package="cn.wxdl.usermanage.repository"
repository-impl-postfix="Impl"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
<!--第五步-->
<!--声明采用注解的方式申明事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
创建类文件并编码
User.java ---- 用户实体类
UserRepository.java ---- 用户的数据接口
UserService.java ---- 用户服务接口
UserServiceImpl.java ---- 接口实现
UserNotFound.java ---- 异常类,未找到记录时抛出
类之间的关系:
实体中常用的注解:
· @ Entity :声明这个类是一个实体类
· @ Table:指定映射到数据库的表格
· @ Id :映射到数据库表的主键属性,一个实体只能有一个属性被映射为主键
· @ GeneratedValue:主键的生成策略
@Entity //这是一个实体类
@Table (name="user") //对应的表名是user
public class User {
@Id //此字段是主键
@GeneratedValue //给定默认的生成策略
private Integer id;
private String name;
private String address;
private String phone;
....实现getter 和 setter 方法...
}
JpaRepository接口常用的方法:
· delete删除或批量删除
· findAll查找所有
· findO ne查找单个
· save保存单个或批量保存
· saveAndFlush保存并刷新到数据库
UserRepository.class
/**注:继承的接口是个泛型 -- 第一个参数是实体类类型.第二个参数是主键类型 */
public interface UserRepository extends JpaRepository<User, Integer>{
//此处是空实现,可以根据需求添加方法
}
UserService.class
public interface UserService {
//添加
public void addUser(User user);
//修改
public User updateUser(User user) throws UserNotFound;
//删除
public User deleteUserById(Integer id) throws UserNotFound;
//根据id查询单条记录
public User getUser(Integer id);
//查询多条记录
public List<User> getUsers();
//根据id判断记录是否存在
public boolean existById(Integer id);
public List<User> pageUsers(Pageable pageable);
}
UserServiceImpl.class
@Service ("userService")
public class UserServiceImpl implements UserService{
//关联了UserRepository 同等与注入dao层的实例
@Autowired
private UserRepository userRepository;
public void addUser(User user) {
userRepository.save(user);
}
//实现UserService中定义的方法
}
之后就可以自己动手写个测试方法进行测试
查询操作的基本实现的方式
· 基于方法名解析的概念
· 方法名 构造方法
· 目前支持的 关键词
· 嵌套实体方法命名规则
基于方法名解析的概念
JpaRepository支持接口规范方法名查询。意思是如果在接口中定义的查询方法符合它的命名规则,就可以不用写实现。
例如:findByName这个方法表示从数据库中查询Name这个属性等于XXX的所有记录,类似于SQ L语句:select * from xxTable where name=xxx这种形式
这段话有两个重点:
1、方法名需要在接口中设定
2、必须符合一定的命名规范
方法名构造方法
find+全局修饰+By+实体的属性名称+限定词+连接词+ ...(其它实体属性)+O rderBy+
排序属性+排序方向
例如:
findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(StringfirstName,String lastName){......}
其中:Distinct是全局修饰(非必须),FirstName和LastName是实体的属性名,
And是连接词,IgnoreCase是限定词,Age是排序属性,Desc是排序方向,限定词
和连接词统称为“关键词”
目前支持的关键词
常用词如下:
全局修饰:Distinct,Top,First
关键词:IsN ull,IsN otN ull,Like,N otLike,Containing,In,N otIn,
IgnoreCase,Betw een,Equals,LessThan,GreaterThan,After,Before...
排序方向:Asc,Desc
连接词:And,O r
更多关键词请查看官方在线文档:
http://docs.spring.io/spring-data/jpa/docs/1.7.2.RELEASE/reference/html/
使用@Query
可以在自定义的查询方法上使用@Query来指定该方法要执行的查询语句
public interface UserRepository extends JpaRepository<User, Integer>{
@Query("select u from User u where u.name = ?1")
public List<User> queryByName(String username);
}
注意:
1:方法的参数个数必须和@Query里面需要的参数个数一致
2:如果是like,后面的参数需要前面或者后面加“%”
使用@Param可以用命名参数来代替位置编号,将方法参数与 JPQL 中的命名参数对应。JPQL 语句中通过": 变量"的格式来指定参数
例:
public interface UserRepository extends JpaRepository<User, Integer> { @Query("select u from User u where u.name = :name and u.phone = :phone") public List<User> queryUser(@Param("name")String name,@Param("phone")String phonenum); } |
如果要生成更新类的Query语句,在@Query之前添加@Modifying即可。
例:
@Modifying @Query("update User u set u.firstname = ?1 where u.lastname = ?2") int setFixedFirstnameFor(String firstname, String lastname); |
注意:
1:方法的返回值应该是int,表示更新语句所影响的行数。
2:在调用的地方必须加事务,没有事务不能正常执行。
使用JPA NamedQueries
在JPA配置文件中定义
在META-INF文件下的JPA的配置文件orm.xml中,通过<named-query/>元素进行定义。
例:
<named-query name="User.findByLastname"> <query>select u from User u where u.lastname = ?1</query> </named-query> |
通过Annotation配置
在Entity Bean中使用@NamedQuery(或@NamedNativeQuery)进行配置。
例:
@Entity @NamedQuery(name = "User.findByEmailAddress", query = "select u from User u where u.emailAddress = ?1") public class User { } |
注意
① 上述两种方法都需要满足”DomainClass.methodName()”的命名规则。
② 无论是在JPA配置文件中使用<named-query/>定义还是在Entity Bean中使用@NamedQuery进行配置,
在持久层的接口中必须声明对应的方法, 例:
public interface UserRepository extends JpaRepository<User, Long> { List<User> findByLastname(String lastname); User findByEmailAddress(String emailAddress); } |
创建Query的策略
创建Query的策略有如下3种:
Ø create:只通过解析方法名来创建Query。忽略@Query和NamedQuery方法。 Ø use-declared-query:如果方法通过 @Query 指定了查询语句,则使用该语句创建Query;如果没有,则查找是否定义了符合条件的Named Query,如果找到,则使用该命名查询;如果两者都没有找到,则抛出异常。 Ø create-if-not-found (default):如果方法通过 @Query 指定了查询语句,则使用该语句创建查询;如果没有,则查找是否定义了符合条件的Named Query,如果找到,则使用该Named Query;如果两者都没有找到,则通过解析方法名字来创建Query。 |
<jpa:repositories>中提供的query-lookup-strategy 属性可以用来定义查找Query的顺序。定义方法如下:
<jpa:repositories base-package=" com.jpa.data.sample" query-lookup-strategy="create"/> |
嵌套实体方法命名规则
构词法:主实体中子实体的名称+ _ +子实体的属性名称
例如:List<Person> findByAddress_ZipCode(ZipCode zipCode)
表示查询所有 Address(地址)的zipCode(邮编)为指定值的所有Person(人员)
转载于:https://my.oschina.net/wxdl/blog/700809