# Spring Boot Data JPA
## 一、项目说明
### 1.1 项目结构
### 1.2 基本依赖
```xml
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
8.0.13
org.springframework.boot
spring-boot-starter-test
test
```
## 二、 使用 Data JPA
### 2.1 数据源配置
在 application.yml 中配置数据源:
```yaml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
#Hibernate 默认创建的表是 myisam 引擎,可以用以下方式指定为使用 innodb 创建表
database-platform: org.hibernate.dialect.MySQL57Dialect
show-sql: true
```
### 2.2 查询接口
```java
/**
* @description : 查询接口继承自 CrudRepository,CrudRepository 默认定义了部分增删改查方法
*/
public interface ProgRepository extends CrudRepository {
/*
* 方法名遵循命名规范的查询 更多命名规范可以参考官方文档所列出的这张表格
*/
List findAllByName(String name);
/*
*分页排序查询
*/
Page findAll(Pageable pageable);
/*
* 占位符查询
*/
@Query(value = "select u from Programmer u where u.name = ?1 or u.salary = ?2")
List findByConditionAndOrder(String name, float salary, Sort.Order order);
/*
* 传入参数名称
*/
@Query("select u from Programmer u where u.name = :name or u.age = :age")
Programmer findByParam(@Param("name") String name,
@Param("age") int age);
}
```
在使用 Spring Data JPA 时你甚至可以不用写 SQL 语句,只需要在定义方法名时满足 Spring 的规范即可,Spring 会自动将这些方法按照其命名转换为对应的 SQL 语句,以下是其转换对照表:
| Keyword | Sample | JPQL snippet |
| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `And` | `findByLastnameAndFirstname` | `… where x.lastname = ?1 and x.firstname = ?2` |
| `Or` | `findByLastnameOrFirstname` | `… where x.lastname = ?1 or x.firstname = ?2` |
| `Is,Equals` | `findByFirstname`,`findByFirstnameIs`,
`findByFirstnameEquals` | `… where x.firstname = ?1` |
| `Between` | `findByStartDateBetween` | `… where x.startDate between ?1 and ?2` |
| `LessThan` | `findByAgeLessThan` | `… where x.age < ?1` |
| `LessThanEqual` | `findByAgeLessThanEqual` | `… where x.age <= ?1` |
| `GreaterThan` | `findByAgeGreaterThan` | `… where x.age > ?1` |
| `GreaterThanEqual` | `findByAgeGreaterThanEqual` | `… where x.age >= ?1` |
| `After` | `findByStartDateAfter` | `… where x.startDate > ?1` |
| `Before` | `findByStartDateBefore` | `… where x.startDate < ?1` |
| `IsNull` | `findByAgeIsNull` | `… where x.age is null` |
| `IsNotNull,NotNull` | `findByAge(Is)NotNull` | `… where x.age not null` |
| `Like` | `findByFirstnameLike` | `… where x.firstname like ?1` |
| `NotLike` | `findByFirstnameNotLike` | `… where x.firstname not like ?1` |
| `StartingWith` | `findByFirstnameStartingWith` | `… where x.firstname like ?1`(parameter bound with appended `%`) |
| `EndingWith` | `findByFirstnameEndingWith` | `… where x.firstname like ?1`(parameter bound with prepended `%`) |
| `Containing` | `findByFirstnameContaining` | `… where x.firstname like ?1`(parameter bound wrapped in `%`) |
| `OrderBy` | `findByAgeOrderByLastnameDesc` | `… where x.age = ?1 order by x.lastname desc` |
| `Not` | `findByLastnameNot` | `… where x.lastname <> ?1` |
| `In` | `findByAgeIn(Collection ages)` | `… where x.age in ?1` |
| `NotIn` | `findByAgeNotIn(Collection ages)` | `… where x.age not in ?1` |
| `True` | `findByActiveTrue()` | `… where x.active = true` |
| `False` | `findByActiveFalse()` | `… where x.active = false` |
| `IgnoreCase` | `findByFirstnameIgnoreCase` | `… where UPPER(x.firstame) = UPPER(?1)` |
### 2.3 单元测试
```java
@RunWith(SpringRunner.class)
@SpringBootTest
public class DataJPATests {
@Autowired
private ProgRepository repository;
/**
* 保存数据测试
*/
@Test
public void save() {
// 保存单条数据
repository.save(new Programmer("pro01", 12, 2121.34f, new Date()));
// 保存多条数据
List programmers = new ArrayList<>();
programmers.add(new Programmer("pro02", 22, 3221.34f, new Date()));
programmers.add(new Programmer("pro03", 32, 3321.34f, new Date()));
programmers.add(new Programmer("pro04", 44, 4561.34f, new Date()));
programmers.add(new Programmer("pro01", 44, 4561.34f, new Date()));
repository.saveAll(programmers);
}
/**
* 查询数据测试
*/
@Test
public void get() {
// 遵循命名规范的查询
List programmers = repository.findAllByName("pro01");
programmers.forEach(System.out::println);
// 传入参数名称
Programmer param = repository.findByParam("pro02", 22);
System.out.println("findByParam:" + param);
// 占位符查询
List byCondition = repository.findByConditionAndOrder("pro03", 3321.34f, Sort.Order.asc("salary"));
System.out.println("byCondition:" + byCondition);
//条件与分页查询 需要注意的是这里的页数是从第 0 页开始计算的
Page page = repository.findAll(PageRequest.of(0, 10, Sort.Direction.DESC, "salary"));
page.get().forEach(System.out::println);
}
/**
* 更新数据测试
*/
@Test
public void update() {
// 保存主键相同的数据就认为是更新操作
repository.save(new Programmer(1, "updatePro01", 12, 2121.34f, new Date()));
Optional programmer = repository.findById(1);
Assert.assertEquals(programmer.get().getName(), "updatePro01");
}
/**
* 删除数据测试
*/
@Test
public void delete() {
Optional programmer = repository.findById(2);
if (programmer.isPresent()) {
repository.deleteById(2);
}
Assert.assertFalse(programmer.isPresent());
}
}
```