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提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可

Spring Data JPA  ——  快速入门

三、快速入门

1、构建demo环境

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

Spring Data JPA  ——  快速入门

  • 导入依赖

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cenobitor</groupId>
<artifactId>JPADemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<description>统一管理依赖</description> <properties>
<spring.version>4.2.4.RELEASE</spring.version>
<hibernate.version>5.0.7.Final</hibernate.version>
<slf4j.version>1.6.6</slf4j.version>
<springdatajpa.version>1.10.4.RELEASE</springdatajpa.version>
<c3p0.version>0.9.1.2</c3p0.version>
<junit.version>4.11</junit.version>
</properties> <dependencies>
<!-- spring 框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency> <!-- spring data jpa 数据库持久层 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${springdatajpa.version}</version>
</dependency> <!-- hibernate 框架 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency> <!-- 数据库连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency> <!-- 日志框架 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency> <!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies> </project>
  • 在applicationContext.xml中增加如下配置

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" 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.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <!--指定连接池配置-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql:///ssh01?useSSL=false" />
<property name="user" value="root" />
<property name="password" value="" />
</bean>
<!-- spring整合JPA -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--指定JPA扫描的实体类所在的包-->
<property name="packagesToScan" value="com.cenobitor.domain" />
<!-- 指定持久层提供者为Hibernate -->
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- 自动建表 -->
<property name="generateDdl" value="true" />
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean> <!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean> <!-- 开启事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!--指定Spring Data JPA要进行扫描的包,该包中的类框架会自动为其创建代理-->
<jpa:repositories base-package="com.cenobitor.dao" /> </beans>
  • 项目中新建com.cenobitor.domain包,创建实体类
 @Entity
@Table
public class User {
@Id
@GeneratedValue
@Column
private Integer id;
@Column
private String name;
@Column
private String password; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
  • 项目中新建com.cenobitor.dao包,创建dao
 // 泛型参数1 : 实体类
// 泛型参数2 : 实体类中主键的类型
@Repository
public interface JpaRepository extends org.springframework.data.jpa.repository.JpaRepository<User,Integer>{ }
  • 在com.cenobitor.test创建测试类,进行测试用例,如果在控制台看到Hibernate输出sql语句,说明操作成功

 @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDataJPATest {
@Autowired
private JpaRepository jpaRepository; @Test
public void testQuery() {
// 查询操作
List<User> list = jpaRepository.findAll();
for (User user : list) {
System.out.println(user);
}
}
}

2、增删改查操作

 @Test
public void testSave() {
// 保存数据
User user = new User();
user.setName("赵六");
user.setPassword("1234"); jpaRepository.save(user);
} @Test
public void testUpdate() {
// 更新操作,传入主键ID
User user = new User();
user.setId(3);
user.setName("李四");
// 调用该方法时,首先进行查询操作,如果数据不存在,执行插入
// 如果数据存在,执行修改
jpaRepository.save(user);
} @Test
public void testDelete() {
//删除操作
jpaRepository.delete(3);
} @Test
public void testFindOne() {
//根据主键进行查询
User user = jpaRepository.findOne(4);
System.out.println(user);
}

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 : 实体类
// 泛型参数2 : 实体类中主键的类型
@Repository
public interface JpaRepository extends org.springframework.data.jpa.repository.JpaRepository<User,Integer>{
// =============标准命名方式===============
// 根据名字进行精准查询,Standard类中有name字段
User findByName(String name);
// 根据名字进行模糊查询
User findByNameLike(String name);
// 查询名字为空的数据
List<User> findByNameIsNull();
// 多条件查询
User findByNameAndPassword(String name,String password);
// ==============非标准命名方式=============
// 使用JPQL进行非标准命名查询
@Query("from User u where u.name like ?")
User findByNamexxxxxLikeJPQL(String name);
// 使用JPQL进行非标准多条件查询
// 默认情况下,问号的顺序和传入的参数顺序是一致的
// 可以在问号后面追加数字,改变和参数的匹配顺序
// 下面的示例中,传入的第一个参数匹配到第二个问号,传入的第二个参数匹配到第一个问号
@Query("from User u where u.name like ?2 and password = ?1")
User findByNameAndOperatorJPQL(String password,String name);
// 使用标准SQL进行非标准命名查询
@Query(value = "select * from user u where u.name like ?", nativeQuery = true)
User findByNamexxxxxLikeSQL(String name);
}
   @Test
public void testFindByName(){
User user = jpaRepository.findByName("赵六");
System.out.println(user);
} @Test
public void testFindByNameLike(){
User user = jpaRepository.findByNameLike("%六");
System.out.println(user);
} @Test
public void testFindByNameIsNull(){
List<User> users = jpaRepository.findByNameIsNull();
System.out.println(users);
} @Test
public void testFindByNameAndPassword(){
User user = jpaRepository.findByNameAndPassword("赵六","1234");
System.out.println(user);
} @Test
public void testFindByNamexxxxxLikeJPQL(){
User user = jpaRepository.findByNamexxxxxLikeJPQL("赵六");
System.out.println(user);
} @Test
public void testFindByNameAndOperatorJPQL(){
User user = jpaRepository.findByNameAndOperatorJPQL("1234","赵六");
System.out.println(user);
} @Test
public void testFindByNamexxxxxLikeSQL(){
User user = jpaRepository.findByNamexxxxxLikeSQL("赵六");
System.out.println(user);
}

4、自定义更新删除操作

 // ================自定义增删改操作==========
@Transactional // 使用事务
@Modifying // 执行修改操作
@Query("delete from User u where u.name = ?")
void deleteByName(String name); @Transactional
@Modifying // 执行修改操作
@Query("update User u set u.password = ?2 where u.name = ?1")
void updatePasswordByName(String name, String password);
     @Test
public void testDeleteByName() {
// 使用JPQL进行自定义删除操作
jpaRepository.deleteByName("赵六");
} @Test
public void testUpdatePasswordByName() {
// 使用JPQL进行自定义更新操作
jpaRepository.updatePasswordByName("赵六","333");
}
5、分页查询与条件分页查询
  • 分页查询
     //分页查询
@Test
public void TestPageQuery() throws IOException {
int page = 1 ; //当前页面
int rows = 10 ; //每页数据条数
//创建分页条件
Pageable pageable = new PageRequest(page - 1, rows);
Page<User> page1 = jpaRepository.findAll(pageable);
//获取总数据条数
long totalElements = page1.getTotalElements();
//获取结果集
List<User> list = page1.getContent();
System.out.println(list); }
  • 条件分页查询
@Repository
public interface JpaRepository extends JpaRepository<User,Integer>,
JpaSpecificationExecutor<User> {
}
 @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDataJPATest {
@Autowired
private JpaRepository jpaRepository; @Test
public void testConditionPageQuery() throws IOException { User user = new User();
user.setName("李%");
user.setPassword("1234"); int page = 1 ; //当前页面
int rows = 10 ; //每页数据条数 //构造查询条件
Specification<User> specification = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
/**
* 创建一个查询的where语句
* @param root : 根对象.可以简单的认为就是泛型对象
* @param cb : 构建查询条件
* @return a {@link Predicate}, must not be {@literal null}.
*/
String name = user.getName();
String password = user.getPassword();
// 存储条件的集合
ArrayList<Predicate> list = new ArrayList<>();
if (! name.isEmpty()){
//构建模糊查询条件,参数2为具体的比较的值
Predicate p1 = cb.like(root.get("name").as(String.class),name);
list.add(p1);
}
if (! password.isEmpty()){
Predicate p2 = cb.equal(root.get("password").as(String.class), password);
list.add(p2);
}
if (list.size() == 0 ){
return null;
}
Predicate[] arr = new Predicate[list.size()];
list.toArray(arr);
return cb.and(arr);
} };
Pageable pageable = new PageRequest(page-1,rows);
Page<User> page1 = jpaRepository.findAll(specification,pageable);
List<User> content = page1.getContent();
System.out.println(content);
}
}
上一篇:C#学习笔记_1


下一篇:Chrome和IE中使用window.open函数