Spring Data JPA —— 快速入门

一、概述

  JPA : Java Persistence API, Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

  Spring Data JPA 是Spring基于ORM框架、JPA规范封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用SpringDataJPA可以极大提高开发效率! 除了CRUD外,还包括如分页、排序等一些常用的功能。下面的示例代码即可完成数据保存的操作,而无需具体实现类.

public interface UserDao extends Repository<AccountInfo, Long> { 
  public AccountInfo save(AccountInfo accountInfo);
}

二、Spring Data JPA的核心接口

  • Repository:最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别。

  • CrudRepository :是Repository的子接口,提供CRUD的功能

  • PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能

  • JpaRepository:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等。

  • JpaSpecificationExecutor:用来做负责查询的接口

  • Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可

 

三、快速入门

1、构建demo环境

  • 使用maven建立jar项目,下图为项目文件目录

  • 导入依赖

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 2          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 3     <modelVersion>4.0.0</modelVersion>
 4     <groupId>com.cenobitor</groupId>
 5     <artifactId>JPADemo</artifactId>
 6     <version>0.0.1-SNAPSHOT</version>
 7     <packaging>pom</packaging>
 8     <description>统一管理依赖</description>
 9 
10     <properties>
11         <spring.version>4.2.4.RELEASE</spring.version>
12         <hibernate.version>5.0.7.Final</hibernate.version>
13         <slf4j.version>1.6.6</slf4j.version>
14         <springdatajpa.version>1.10.4.RELEASE</springdatajpa.version>
15         <c3p0.version>0.9.1.2</c3p0.version>
16         <junit.version>4.11</junit.version>
17     </properties>
18 
19     <dependencies>
20         <!-- spring 框架 -->
21         <dependency>
22             <groupId>org.springframework</groupId>
23             <artifactId>spring-context</artifactId>
24             <version>${spring.version}</version>
25         </dependency>
26 
27         <dependency>
28             <groupId>org.springframework</groupId>
29             <artifactId>spring-test</artifactId>
30             <version>${spring.version}</version>
31         </dependency>
32 
33 
34         <!-- spring data jpa 数据库持久层 -->
35         <dependency>
36             <groupId>org.springframework.data</groupId>
37             <artifactId>spring-data-jpa</artifactId>
38             <version>${springdatajpa.version}</version>
39         </dependency>
40 
41         <!-- hibernate 框架 -->
42         <dependency>
43             <groupId>org.hibernate</groupId>
44             <artifactId>hibernate-core</artifactId>
45             <version>${hibernate.version}</version>
46         </dependency>
47         <dependency>
48             <groupId>org.hibernate</groupId>
49             <artifactId>hibernate-entitymanager</artifactId>
50             <version>${hibernate.version}</version>
51         </dependency>
52 
53         <!-- 数据库连接池 -->
54         <dependency>
55             <groupId>c3p0</groupId>
56             <artifactId>c3p0</artifactId>
57             <version>${c3p0.version}</version>
58         </dependency>
59 
60         <!-- 日志框架 -->
61         <dependency>
62             <groupId>org.slf4j</groupId>
63             <artifactId>slf4j-log4j12</artifactId>
64             <version>${slf4j.version}</version>
65         </dependency>
66         <!-- 数据库驱动 -->
67         <dependency>
68             <groupId>mysql</groupId>
69             <artifactId>mysql-connector-java</artifactId>
70             <version>5.1.6</version>
71         </dependency>
72 
73         <!-- 单元测试 -->
74         <dependency>
75             <groupId>junit</groupId>
76             <artifactId>junit</artifactId>
77             <version>${junit.version}</version>
78         </dependency>
79     </dependencies>
80 
81 </project>
  • 在applicationContext.xml中增加如下配置

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
 5        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
 6        xsi:schemaLocation="
 7                         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 8                         http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
 9                         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
10                         http://www.springframework.org/schema/data/jpa
11                         http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
12 
13     <!--指定连接池配置-->
14     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
15         <property name="driverClass" value="com.mysql.jdbc.Driver" />
16         <property name="jdbcUrl" value="jdbc:mysql:///ssh01?useSSL=false" />
17         <property name="user" value="root" />
18         <property name="password" value="" />
19     </bean>
20     <!-- spring整合JPA -->
21     <bean id="entityManagerFactory"
22         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
23         <property name="dataSource" ref="dataSource" />
24         <!--指定JPA扫描的实体类所在的包-->
25         <property name="packagesToScan" value="com.cenobitor.domain" />
26         <!-- 指定持久层提供者为Hibernate -->
27         <property name="persistenceProvider">
28             <bean class="org.hibernate.ejb.HibernatePersistence" />
29         </property>
30         <property name="jpaVendorAdapter">
31             <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
32                 <!-- 自动建表 -->
33                 <property name="generateDdl" value="true" />
34                 <property name="database" value="MYSQL" />
35                 <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
36                 <property name="showSql" value="true" />
37             </bean>
38         </property>
39         <property name="jpaDialect">
40             <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
41         </property>
42     </bean>
43 
44     <!-- 配置事务管理器 -->
45     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
46         <property name="entityManagerFactory" ref="entityManagerFactory" />
47     </bean>
48 
49     <!-- 开启事务注解 -->
50     <tx:annotation-driven transaction-manager="transactionManager" />
51     <!--指定Spring Data JPA要进行扫描的包,该包中的类框架会自动为其创建代理-->
52     <jpa:repositories base-package="com.cenobitor.dao" />
53 
54 </beans>
  • 项目中新建com.cenobitor.domain包,创建实体类
 1 @Entity
 2 @Table
 3 public class User {
 4     @Id
 5     @GeneratedValue
 6     @Column
 7     private Integer id;
 8     @Column
 9     private String name;
10     @Column
11     private String password;
12 
13     public Integer getId() {
14         return id;
15     }
16 
17     public void setId(Integer id) {
18         this.id = id;
19     }
20 
21     public String getName() {
22         return name;
23     }
24 
25     public void setName(String name) {
26         this.name = name;
27     }
28 
29     public String getPassword() {
30         return password;
31     }
32 
33     public void setPassword(String password) {
34         this.password = password;
35     }
36 
37     @Override
38     public String toString() {
39         return "User{" +
40                 "id=" + id +
41                 ", name='" + name + '\'' +
42                 ", password='" + password + '\'' +
43                 '}';
44     }
45 }
  • 项目中新建com.cenobitor.dao包,创建dao
1 // 泛型参数1 : 实体类
2 // 泛型参数2 : 实体类中主键的类型
3 @Repository
4 public interface JpaRepository extends org.springframework.data.jpa.repository.JpaRepository<User,Integer>{
5 
6 }
  • 在com.cenobitor.test创建测试类,进行测试用例,如果在控制台看到Hibernate输出sql语句,说明操作成功

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext.xml")
 3 public class SpringDataJPATest {
 4     @Autowired
 5     private JpaRepository jpaRepository;
 6 
 7     @Test
 8     public void testQuery() {
 9         // 查询操作
10         List<User> list = jpaRepository.findAll();
11         for (User user : list) {
12             System.out.println(user);
13         }
14     }
15 }

2、增删改查操作

 1 @Test
 2     public void testSave() {
 3         // 保存数据
 4         User user = new User();
 5         user.setName("赵六");
 6         user.setPassword("1234");
 7 
 8         jpaRepository.save(user);
 9     }
10 
11     @Test
12     public void testUpdate() {
13         // 更新操作,传入主键ID
14         User user = new User();
15         user.setId(3);
16         user.setName("李四");
17         // 调用该方法时,首先进行查询操作,如果数据不存在,执行插入
18         // 如果数据存在,执行修改
19         jpaRepository.save(user);
20     }
21 
22     @Test
23     public void testDelete() {
24         //删除操作
25         jpaRepository.delete(3);
26     }
27 
28     @Test
29     public void testFindOne() {
30         //根据主键进行查询
31         User user = jpaRepository.findOne(4);
32         System.out.println(user);
33     }

3、自定义查询操作

  JpaRepository支持接口规范方法名查询。意思是如果在接口中定义的查询方法符合它的命名规则,就可以不用写实现。

  例如:findByName这个方法表示从数据库中查询Name这个属性等于XXX的所有记 录,类似于SQL语句:select*from xTablewherename=x这种形式 这段话有两个重点:

①方法名需要在接口中设定

②必须符合一定的命名规范 

  • 方法名构造方法

  find+全局修饰+By+实体的属性名称+限定词+连接词+.(其它实体属性)+OrderBy+ 排序属性+排序方向
  例如:

findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(String firstName,StringlastName){.} 

  其中:Distinct是全局修饰(非必须),FirstName和LastName是实体的属性名, And是连接词,IgnoreCase是限定词,Age是排序属性,Desc是排序方向,限定词 和连接词统称为“关键词” 

  • 常用词如下:
    • 全局修饰:Distinct,Top,First
    • 关键词:IsNull,IsNotNull,Like,NotLike,Containing,In,NotIn, IgnoreCase,Between,Equals,LesThan,GreaterThan,After,Before
    • 排序方向:Asc,Desc
    • 连接词:And,Or
  • 示例
 1 // 泛型参数1 : 实体类
 2 // 泛型参数2 : 实体类中主键的类型
 3 @Repository
 4 public interface JpaRepository extends org.springframework.data.jpa.repository.JpaRepository<User,Integer>{
 5     // =============标准命名方式===============
 6     // 根据名字进行精准查询,Standard类中有name字段
 7     User findByName(String name);
 8     // 根据名字进行模糊查询
 9     User findByNameLike(String name);
10     // 查询名字为空的数据
11     List<User> findByNameIsNull();
12     // 多条件查询
13     User findByNameAndPassword(String name,String password);
14     // ==============非标准命名方式=============
15     // 使用JPQL进行非标准命名查询
16     @Query("from User u where u.name like ?")
17     User findByNamexxxxxLikeJPQL(String name);
18     // 使用JPQL进行非标准多条件查询
19     // 默认情况下,问号的顺序和传入的参数顺序是一致的
20     // 可以在问号后面追加数字,改变和参数的匹配顺序
21     // 下面的示例中,传入的第一个参数匹配到第二个问号,传入的第二个参数匹配到第一个问号
22     @Query("from User u where u.name like ?2 and password = ?1")
23     User findByNameAndOperatorJPQL(String password,String name);
24     // 使用标准SQL进行非标准命名查询
25     @Query(value = "select * from user u where u.name like ?", nativeQuery = true)
26     User findByNamexxxxxLikeSQL(String name);
27 }
 1   @Test
 2     public void testFindByName(){
 3         User user = jpaRepository.findByName("赵六");
 4         System.out.println(user);
 5     }
 6 
 7     @Test
 8     public void testFindByNameLike(){
 9         User user = jpaRepository.findByNameLike("%六");
10         System.out.println(user);
11     }
12 
13     @Test
14     public void testFindByNameIsNull(){
15         List<User> users = jpaRepository.findByNameIsNull();
16         System.out.println(users);
17     }
18 
19     @Test
20     public void testFindByNameAndPassword(){
21         User user = jpaRepository.findByNameAndPassword("赵六","1234");
22         System.out.println(user);
23     }
24 
25     @Test
26     public void testFindByNamexxxxxLikeJPQL(){
27         User user = jpaRepository.findByNamexxxxxLikeJPQL("赵六");
28         System.out.println(user);
29     }
30 
31     @Test
32     public void testFindByNameAndOperatorJPQL(){
33         User user = jpaRepository.findByNameAndOperatorJPQL("1234","赵六");
34         System.out.println(user);
35     }
36 
37     @Test
38     public void testFindByNamexxxxxLikeSQL(){
39         User user = jpaRepository.findByNamexxxxxLikeSQL("赵六");
40         System.out.println(user);
41     }

4、自定义更新删除操作

 1 // ================自定义增删改操作==========
 2     @Transactional // 使用事务
 3     @Modifying // 执行修改操作
 4     @Query("delete from User u where u.name = ?")
 5     void deleteByName(String name);
 6 
 7     @Transactional
 8     @Modifying // 执行修改操作
 9     @Query("update User u set u.password = ?2 where u.name = ?1")
10     void updatePasswordByName(String name, String password);
 1     @Test
 2     public void testDeleteByName() {
 3         // 使用JPQL进行自定义删除操作
 4         jpaRepository.deleteByName("赵六");
 5     }
 6 
 7     @Test
 8     public void testUpdatePasswordByName() {
 9         // 使用JPQL进行自定义更新操作
10         jpaRepository.updatePasswordByName("赵六","333");
11     }
5、分页查询与条件分页查询
  • 分页查询
 1     //分页查询
 2     @Test
 3     public void TestPageQuery() throws IOException {
 4         int page = 1 ;  //当前页面
 5         int rows = 10 ; //每页数据条数
 6         //创建分页条件
 7         Pageable pageable = new PageRequest(page - 1, rows);
 8         Page<User> page1 = jpaRepository.findAll(pageable);
 9         //获取总数据条数
10         long totalElements = page1.getTotalElements();
11         //获取结果集
12         List<User> list = page1.getContent();
13         System.out.println(list);
14 
15     }
  • 条件分页查询
@Repository
public interface JpaRepository extends JpaRepository<User,Integer>,
        JpaSpecificationExecutor<User> {
}
 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext.xml")
 3 public class SpringDataJPATest {
 4     @Autowired
 5     private JpaRepository jpaRepository;
 6 
 7     @Test
 8     public void testConditionPageQuery() throws IOException {
 9 
10         User user = new User();
11         user.setName("李%");
12         user.setPassword("1234");
13 
14         int page = 1 ;  //当前页面
15         int rows = 10 ; //每页数据条数
16 
17         //构造查询条件
18         Specification<User> specification = new Specification<User>() {
19             @Override
20             public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
21                 /**
22                  * 创建一个查询的where语句
23                  * @param root : 根对象.可以简单的认为就是泛型对象
24                  * @param cb : 构建查询条件
25                  * @return a {@link Predicate}, must not be {@literal null}.
26                  */
27                 String name = user.getName();
28                 String password = user.getPassword();
29                 // 存储条件的集合
30                 ArrayList<Predicate> list = new ArrayList<>();
31                 if (! name.isEmpty()){
32                     //构建模糊查询条件,参数2为具体的比较的值
33                     Predicate p1 = cb.like(root.get("name").as(String.class),name);
34                     list.add(p1);
35                 }
36                 if (! password.isEmpty()){
37                     Predicate p2 = cb.equal(root.get("password").as(String.class), password);
38                     list.add(p2);
39                 }
40                 if (list.size() == 0 ){
41                     return null;
42                 }
43                 Predicate[] arr = new Predicate[list.size()];
44                 list.toArray(arr);
45                 return cb.and(arr);
46             }
47 
48         };
49         Pageable pageable = new PageRequest(page-1,rows);
50         Page<User> page1 = jpaRepository.findAll(specification,pageable);
51         List<User> content = page1.getContent();
52         System.out.println(content);
53     }
54 }
posted @ 2018-03-20 20:24  gdwkong  阅读(4203)  评论(0编辑  收藏  举报