概述
JPA为对象关系映射提供了一种基于POJO的持久化模型,简化数据持久化代码的开发工作,为Java社区屏蔽不同的持久化API的差异
JPA常用注解
@Entity
每个持久化POJO类都是一个实体Bean,通过在类的定义中使用@Entity 注解来进行声明 ,将映射到指定的数据库表。如声明一个实体类Customer,将它映射到数据的coustomer表上
@Table
声明此对象映射到数据库的数据表。该注释不是必需的,如果没有, 系统就会使用默认值(实体的短类名)。@Table标注的常用选项是name,用于指明数据库的表名。
@Id
@GeneratedValue
用于标注主键的生成策略,通过strategy属性指定。默认情况下,JPA自动选择一个最合适底层数据库的主键生成策略:SqlServer对应identity,MySql对饮auto increment。
JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO.
TABLE:使用一个特定的数据库表格来保存主键。
SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
IDENTITY:主键由数据库自动生成(主要是自动增长型)
AUTO:主键由程序控制
@Column
- 当实体的属性与其映射的数据库表的列不同名时需要使用@Column标注说明,该属性通常置于实体的属性声明语句之前,还可与@Id标注一起使用。
- @Column标注的常量属性是name,用于设置映射数据库表的列名。此外,该注解还包含其他多个属性,比如:unique,nullable,length等。
@Column标注的columnDefinition属性:表示该字段在数据中的实际类型,通常ORM框架可以根据属性类型自动判断数据中的字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是Date,Time还是Timestamp。此外,String的默认类型为varchar,如果要将String类型映射到特定数据库的BLOB或Text字段类型。
@Transient
表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性。
如果一个属性并非数据库的字段映射,就务必将其标示为@Transient
@Temporal
在核心的JAVA API中并没有定义Date类型的精度(temporal precision)。而在数据库中,表示Date类型的数据类型有DATE,TIME和TEIMSTAMP三种精度(即单纯的日期,时间,或者两者兼备)。在运行属性映射是可使用
-
@DynamicUpdate
添加依赖
项目根目录
pom.xml
添加依赖spring-boot-starter-data-jpa
mysql-connector-java
```org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web mysql mysql-connector-java runtime org.springframework.boot spring-boot-starter-test test
<a name="whSmi"></a>
## 修改配置文件
`application.yml`
```yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: 123456
jpa:
database: mysql
hibernate:
ddl-auto: create
show-sql: true
database-platform: org.hibernate.dialect.MySQL55Dialect
mysql相关配置
datasource
数据源hibernate
: 相关配置信息有以下几种类型ddl-auto:create
: 每次运行加载不管之前是否有数据都会自动创建一个表,会造成数据丢失。ddl-auto:update
: 第一次加载会创建新的数据接口,之后只会在原有表基础之上进行迭代。ddl-auto:validate
: 验证类里面的属性与表结构是否一致。ddl-auto:create-drop
: 每次退出时删除。ddl-auto:node
: 默认什么都不做。
show-sql
: 是否打印SQL,在开发时可以开启方便调试。-
CRUD操作
创建表
就是创建存储的User实体(User类)
是不需要手动去数据库创建表的,以下创建的User类和定义的属性会对应到数据库中的表和字段,这就需要应用jpa的特性了,看下以下注解。
@Entity
: 代表此类映射为数据库的表结构@Id
: 指定一个主键@GeneratedValue
: 配置主键相关信息Table
: 使用一个特定的数据库表来保存主键IDENTITY
: 数据库自动生成AUTO
: 主键由程序控制,默认值SEQUENCE
: 通过数据库的序列产生主键,MYSQL
不支持,部分数据库(Oracle,PostgreSQL,DB2)
支持序列对象
User.java
package com.github.springboot.domain;
import javax.persistence.*;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(length = 128,nullable = false)
private String name;
private Integer age;
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
创建数据访问接口
Repository类下没有任何接口,只是一个空类。Repository接口的子类有CrudRepository、 PagingAndSortingRepository 、 JpaRepository等。其中,CrudRepository类提供了基本的增删改查等接口 , PagingAndSortingRepository类提供了基本的分页和排序等接口,而JpaRepository是CrudRepository 和 PagingAndSortingRepository 的子类 , 继承了它们的所有接口 。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.jpa.repository;
import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
通过下面继承图可以知道接口的继承关系,一般都是都是JpaRepository类,加上自定义方法完成业务开发
创建接口User的数据访问UserRepository继承于JpaRepository
package com.github.springboot.repository;
import com.github.springboot.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface UserRepository extends JpaRepository<User,Integer> {
public List<User>findByName(String name);
}
创建UserController
UserController.java
保存一个用户
package com.github.springboot.controller;
import com.github.springboot.domain.User;
import com.github.springboot.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("api/v1/user")
public class UserController {
@Autowired
private UserRepository userRepository;
@PostMapping()
public User userAdd(@RequestBody User user){
return userRepository.save(user);
}
@GetMapping("list")
public List<User> userList() {
return userRepository.findAll();
}
@GetMapping("{id}")
public Optional<User> userFindOne(@PathVariable("id") Integer id) {
return userRepository.findById(id);
}
@GetMapping()
public List<User> findUserListByName(@RequestParam(name="name",required = true) String name) {
return userRepository.findByName(name);
}
@PutMapping(value = "{id}")
public User userUpdate(@PathVariable("id") Integer id, @RequestParam("name") String name,
@RequestParam("age") Integer age) {
User user = new User();
user.setId(id);
user.setName(name);
user.setAge(age);
return userRepository.save(user);
}
@DeleteMapping("{id}")
public void deleteUser(@PathVariable("id") Integer id) {
userRepository.deleteById(id);
}
}
注意, spring-data-jpa 2.0.5.RELEASE 版本之后获取单个对象的数据源需要用findById()
,SpringBoot1.x版本可以使用findOne()
Github 地址 https://github.com/baxiang/SpringBoot-Note/tree/master/springboot-jpa
curl 测试
增加用户数据
curl -X POST 'http://127.0.0.1:8080/api/v1/user' -d '{"name":"qiang","age":30}' -H 'Content-Type: application/json'
{"id":1,"name":"qiang","age":30}% ➜ springboot-jpa git:(master) ✗ curl -X POST 'http://127.0.0.1:8080/api/v1/user' -d '{"name":"ming","age":20}' -H 'Content-Type: application/json'
✗ curl -X POST 'http://127.0.0.1:8080/api/v1/user' -d '{"name":"ming","age":20}' -H 'Content-Type: application/json'
{"id":2,"name":"ming","age":20}%
查询用户数据
curl -X GET 'http://localhost:8080/api/v1/user/list'
[{"id":1,"name":"qiang","age":30},{"id":2,"name":"ming","age":20}]%
按照id 查询
curl -X GET 'http://localhost:8080/api/v1/user/1'
{"id":1,"name":"qiang","age":30}
安装名称查询
curl -X GET 'http://localhost:8080/api/v1/user?name=ming'
[{"id":2,"name":"ming","age":20}]%
修改用户数据
curl -X PUT 'http://127.0.0.1:8080/api/v1/user/1?name=hong&age=18'
{"id":1,"name":"hong","age":18}
删除用户数据
curl -X DELETE 'http://127.0.0.1:8080/api/v1/user/1'
参考
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories