概述

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三种精度(即单纯的日期,时间,或者两者兼备)。在运行属性映射是可使用

  • @Temporal注解来调整Date精度。

    @DynamicUpdate

    它确保Hibernate只更新实体中修改的列

    添加依赖

    项目根目录 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
  1. <a name="whSmi"></a>
  2. ## 修改配置文件
  3. `application.yml`
  4. ```yaml
  5. spring:
  6. datasource:
  7. driver-class-name: com.mysql.cj.jdbc.Driver
  8. url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=true
  9. username: root
  10. password: 123456
  11. jpa:
  12. database: mysql
  13. hibernate:
  14. ddl-auto: create
  15. show-sql: true
  16. database-platform: org.hibernate.dialect.MySQL55Dialect

mysql相关配置

  • datasource 数据源

    • driver-class-name 驱动名称
    • url 数据库地址(hots:port/database)
    • username 数据库用户名
    • password 数据库密码

      jpa相关配置

  • hibernate: 相关配置信息有以下几种类型

    • ddl-auto:create: 每次运行加载不管之前是否有数据都会自动创建一个表,会造成数据丢失。
    • ddl-auto:update: 第一次加载会创建新的数据接口,之后只会在原有表基础之上进行迭代。
    • ddl-auto:validate: 验证类里面的属性与表结构是否一致。
    • ddl-auto:create-drop: 每次退出时删除。
    • ddl-auto:node: 默认什么都不做。
  • show-sql: 是否打印SQL,在开发时可以开启方便调试。
  • database: 数据库类型。

    CRUD操作

    创建表

    就是创建存储的User实体(User类)

    是不需要手动去数据库创建表的,以下创建的User类和定义的属性会对应到数据库中的表和字段,这就需要应用jpa的特性了,看下以下注解。

  • @Entity: 代表此类映射为数据库的表结构

  • @Id: 指定一个主键
  • @GeneratedValue: 配置主键相关信息
    • Table: 使用一个特定的数据库表来保存主键
    • IDENTITY: 数据库自动生成
    • AUTO: 主键由程序控制,默认值
    • SEQUENCE: 通过数据库的序列产生主键, MYSQL不支持,部分数据库(Oracle,PostgreSQL,DB2)支持序列对象

User.java

  1. package com.github.springboot.domain;
  2. import javax.persistence.*;
  3. @Entity
  4. public class User {
  5. @Id
  6. @GeneratedValue(strategy = GenerationType.IDENTITY)
  7. private Integer id;
  8. @Column(length = 128,nullable = false)
  9. private String name;
  10. private Integer age;
  11. public Integer getId() {
  12. return id;
  13. }
  14. public void setId(Integer id) {
  15. this.id = id;
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public Integer getAge() {
  24. return age;
  25. }
  26. public void setAge(Integer age) {
  27. this.age = age;
  28. }
  29. }

创建数据访问接口

Repository类下没有任何接口,只是一个空类。Repository接口的子类有CrudRepository、 PagingAndSortingRepository 、 JpaRepository等。其中,CrudRepository类提供了基本的增删改查等接口 , PagingAndSortingRepository类提供了基本的分页和排序等接口,而JpaRepository是CrudRepository 和 PagingAndSortingRepository 的子类 , 继承了它们的所有接口 。

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.springframework.data.jpa.repository;
  6. import java.util.List;
  7. import org.springframework.data.domain.Example;
  8. import org.springframework.data.domain.Sort;
  9. import org.springframework.data.repository.NoRepositoryBean;
  10. import org.springframework.data.repository.PagingAndSortingRepository;
  11. import org.springframework.data.repository.query.QueryByExampleExecutor;
  12. @NoRepositoryBean
  13. public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
  14. List<T> findAll();
  15. List<T> findAll(Sort var1);
  16. List<T> findAllById(Iterable<ID> var1);
  17. <S extends T> List<S> saveAll(Iterable<S> var1);
  18. void flush();
  19. <S extends T> S saveAndFlush(S var1);
  20. void deleteInBatch(Iterable<T> var1);
  21. void deleteAllInBatch();
  22. T getOne(ID var1);
  23. <S extends T> List<S> findAll(Example<S> var1);
  24. <S extends T> List<S> findAll(Example<S> var1, Sort var2);
  25. }

通过下面继承图可以知道接口的继承关系,一般都是都是JpaRepository类,加上自定义方法完成业务开发

image.png
创建接口User的数据访问UserRepository继承于JpaRepository

  1. package com.github.springboot.repository;
  2. import com.github.springboot.domain.User;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import java.util.List;
  5. public interface UserRepository extends JpaRepository<User,Integer> {
  6. public List<User>findByName(String name);
  7. }

创建UserController

UserController.java保存一个用户

  1. package com.github.springboot.controller;
  2. import com.github.springboot.domain.User;
  3. import com.github.springboot.repository.UserRepository;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.*;
  6. import java.util.List;
  7. import java.util.Optional;
  8. @RestController
  9. @RequestMapping("api/v1/user")
  10. public class UserController {
  11. @Autowired
  12. private UserRepository userRepository;
  13. @PostMapping()
  14. public User userAdd(@RequestBody User user){
  15. return userRepository.save(user);
  16. }
  17. @GetMapping("list")
  18. public List<User> userList() {
  19. return userRepository.findAll();
  20. }
  21. @GetMapping("{id}")
  22. public Optional<User> userFindOne(@PathVariable("id") Integer id) {
  23. return userRepository.findById(id);
  24. }
  25. @GetMapping()
  26. public List<User> findUserListByName(@RequestParam(name="name",required = true) String name) {
  27. return userRepository.findByName(name);
  28. }
  29. @PutMapping(value = "{id}")
  30. public User userUpdate(@PathVariable("id") Integer id, @RequestParam("name") String name,
  31. @RequestParam("age") Integer age) {
  32. User user = new User();
  33. user.setId(id);
  34. user.setName(name);
  35. user.setAge(age);
  36. return userRepository.save(user);
  37. }
  38. @DeleteMapping("{id}")
  39. public void deleteUser(@PathVariable("id") Integer id) {
  40. userRepository.deleteById(id);
  41. }
  42. }

注意, spring-data-jpa 2.0.5.RELEASE 版本之后获取单个对象的数据源需要用findById(),SpringBoot1.x版本可以使用findOne()

Github 地址 https://github.com/baxiang/SpringBoot-Note/tree/master/springboot-jpa

curl 测试

增加用户数据

  1. curl -X POST 'http://127.0.0.1:8080/api/v1/user' -d '{"name":"qiang","age":30}' -H 'Content-Type: application/json'
  2. {"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'
  3. curl -X POST 'http://127.0.0.1:8080/api/v1/user' -d '{"name":"ming","age":20}' -H 'Content-Type: application/json'
  4. {"id":2,"name":"ming","age":20}%

查询用户数据

  1. curl -X GET 'http://localhost:8080/api/v1/user/list'
  2. [{"id":1,"name":"qiang","age":30},{"id":2,"name":"ming","age":20}]%

按照id 查询

  1. curl -X GET 'http://localhost:8080/api/v1/user/1'
  2. {"id":1,"name":"qiang","age":30}

安装名称查询

  1. curl -X GET 'http://localhost:8080/api/v1/user?name=ming'
  2. [{"id":2,"name":"ming","age":20}]%

修改用户数据

  1. curl -X PUT 'http://127.0.0.1:8080/api/v1/user/1?name=hong&age=18'
  2. {"id":1,"name":"hong","age":18}

删除用户数据

  1. 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

https://www.iocoder.cn/Spring-Data-JPA/good-collection/