摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/JPA/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文,我们基于 Spring Boot 2.X 版本。
我们,咱们来学习下 Spring Data JPA 。
相信不少胖友之前有了解过 JPA、Hibernate ,那么 JPA、Hibernate、Spring Data JPA 这三者是什么关系呢?我们来一起理一理。
JPA ,全称 Java Persistence API ,是由 Java 定义的 Java ORM 以及实体操作 API 的标准。正如最早学习 JDBC 规范,Java 自身并未提供相关的实现,而是 MySQL 提供 MySQL mysql-connector-java 驱动,Oracle 提供 oracle-jdbc 驱动。而实现 JPA 规范的有:
Spring Data JPA ,是 Spring Data 提供的一套简化的 JPA 开发的框架。
@Query
注解,自定义 SQL 。所以,绝大多数情况下,我们无需编写代码,直接调用 JPA 的 API 。也因此,在我们使用的 Spring Data JPA 的项目中,如果想要替换底层使用的 JPA 实现框架,在未使用到相关 JPA 实现框架的特殊特性的情况下,可以透明替换。
关于这一点,我们在 《芋道 Spring Boot Redis 入门》 中,已经看到 Spring Data Redis 也是已经看到这样的好处。
总的来说,就是如下一张图:
FROM 《spring data jpa hibernate jpa 三者之间的关系》
当然,绝大多数情况下,我们使用的 JPA 实现框架是 Hibernate ORM 。所以整个调用过程是:
应用程序 => Repository => Spring Data JPA => Hibernate
示例代码对应仓库:lab-13-jpa 。
本小节,我们会使用 spring-boot-starter-data-jpa
自动化配置 Spring Data JPA 。同时,演示 Spring Data JPA 的 CRUD 的操作。
在 pom.xml
文件中,引入相关依赖。
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-13-jpa</artifactId>
<dependencies>
<!-- 实现对数据库连接池的自动化配置 -->
<!-- 实际上 spring-boot-starter-data-jpa 已经包括 spring-boot-starter-jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <!-- 本示例,我们使用 MySQL -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<!-- 实现对 Spring Data JPA 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 方便等会写单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
具体每个依赖的作用,胖友自己认真看下艿艿添加的所有注释噢。
另外,在 spring-boot-starter-data-jpa
中,已经默认引入了 Hibernate 的依赖。
创建 Application.java
类,配置 @SpringBootApplication
注解即可。代码如下:
// Application.java
@SpringBootApplication
public class Application {
}
在 application.yml
中,添加 JPA 配置,如下:
spring:
# datasource 数据源配置内容
datasource:
url: jdbc:mysql://47.112.193.81:3306/testb5f4?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: testb5f4
password: F4df4db0ed86@11
# JPA 配置内容,对应 JpaProperties 类
jpa:
show-sql: true # 打印 SQL 。生产环境,建议关闭
# Hibernate 配置内容,对应 HibernateProperties 类
hibernate:
ddl-auto: none
datasource
配置项,配置 datasource 数据源配置内容。jpa
配置项,配置 Spring Data JPA 配置内容,对应 `org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.java` 类。hibernate
配置项,配置 Hibernate 配置内容,对应 org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.java
类。none
,不使用 Hibernate Auto DDL 功能。? 启动个项目,就自动变更数据库表结构,多危险啊~hibernate
配置项,这里仅仅是演示,让胖友知道这回事。ddl-auto
配置项,设置 Hibernate DDL 处理策略。一共有 none
、create
、create-drop
、update
、validate
五个选项。
FROM 《jpa 的 hibernate.ddl-auto 的几个属性值区别》在 cn.iocoder.springboot.lab13.jpa.dataobject
包路径下,创建 UserDO.java 类,用户 DO 。代码如下:
// UserDO.java
@Entity
@Table(name = "users")
public class UserDO {
/**
* 用户编号
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, // strategy 设置使用数据库主键自增策略;
generator = "JDBC") // generator 设置插入完成后,查询最后生成的 ID 填充到该属性中。
private Integer id;
/**
* 账号
*/
@Column(nullable = false)
private String username;
/**
* 密码(明文)
*
* ps:生产环境下,千万不要明文噢
*/
@Column(nullable = false)
private String password;
/**
* 创建时间
*/
@Column(name = "create_time", nullable = false)
private Date createTime;
// ... 省略 setting/getting 方法
}
关于 JPA 的注解的详细说明,胖友后面再看看 《Spring Data JPA 中常用的注解详解》 文章。我们,继续往下看。
对应的创建表的 SQL 如下:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户编号',
`username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '账号',
`password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
在 cn.iocoder.springboot.lab13.mybatis.repository
包路径下,创建 UserRepository01 接口。代码如下:
// UserRepository01.java
public interface UserRepository01 extends CrudRepository<UserDO, Integer> {
}
org.springframework.data.repository.CrudRepository
接口,第一个泛型设置对应的实体是 UserDO ,第二个泛型设置对应的主键类型是 Integer 。创建 UserRepository01Test 测试类,我们来测试一下简单的 UserRepository01 的每个操作。代码如下:
// UserRepository01.java
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() {
UserDO user = new UserDO().setUsername(UUID.randomUUID().toString())
.setPassword("nicai").setCreateTime(new Date());
userMapper.insert(user);
}
@Test
public void testUpdateById() {
UserDO updateUser = new UserDO().setId(1)
.setPassword("wobucai");
userMapper.updateById(updateUser);
}
@Test
public void testDeleteById() {
userMapper.deleteById(2);
}
@Test
public void testSelectById() {
userMapper.selectById(1);
}
@Test
public void testSelectByUsername() {
userMapper.selectByUsername("yunai");
}
@Test
public void testSelectByIds() {
List<UserDO> users = userMapper.selectByIds(Arrays.asList(1, 3));
System.out.println("users:" + users.size());
}
}
具体的,胖友可以自己跑跑,妥妥的。
示例代码对应仓库:lab-13-jpa 。
Spring Data 提供 org.springframework.data.repository.PagingAndSortingRepository
接口,继承 CrudRepository 接口,在 CRUD 操作的基础上,额外提供分页和排序的操作。代码如下:
// PagingAndSortingRepository.java
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort); // 排序操作
Page<T> findAll(Pageable pageable); // 分页操作
}
在 cn.iocoder.springboot.lab13.mybatis.repository
包路径下,创建 UserRepository02 接口。代码如下:
// UserRepository02.java
public interface UserRepository02 extends PagingAndSortingRepository<UserDO, Integer> {
}
创建 UserRepository02Test 测试类,我们来测试一下简单的 UserRepository02 的每个操作。代码如下:
// UserRepository02Test.java
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserRepository02Test {
@Autowired
private UserRepository02 userRepository;
@Test // 排序
public void testFindAll() {
// 创建排序条件
Sort sort = new Sort(Sort.Direction.DESC, "id");
// 执行排序操作
Iterable<UserDO> iterable = userRepository.findAll(sort);
// 打印
iterable.forEach(System.out::println);
}
@Test // 分页
public void testFindPage() {
// 创建排序条件
Sort sort = new Sort(Sort.Direction.DESC, "id");
// 创建分页条件
Pageable pageable = PageRequest.of(1, 10, sort);
// 执行分页操作
Page<UserDO> page = userRepository.findAll(pageable);
// 打印
System.out.println(page.getTotalElements());
System.out.println(page.getTotalPages());
}
}
具体的,胖友可以自己跑跑,妥妥的。