spring boot 六:SpringBoot整合JPA

1 前言

JPA: 即java persistence api(Java持久性API)。JPA通过JDK5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

实体类创建后,一般接下来需要手动编写建表语句,方便起见,可利用Hibernate-JPA进行建表。

依赖配置

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.5.4</version>
</parent>

<dependencies>
	<!--    SpringBoot整合JPA依赖    -->
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-data-jpa</artifactId>
	</dependency>
	
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	</dependency>
	
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	
</dependencies>

spring-boot-starter-parent中的parent:spring-boot-dependencies,有依赖的jpa版本2.5.4,以及mysql-connector-java的版本8.0.26:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
  <version>2.5.4</version>
</dependency>
<mysql.version>8.0.26</mysql.version>

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>${mysql.version}</version>
  <exclusions>
    <exclusion>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
    </exclusion>
  </exclusions>
</dependency>

2 使用

2.1 建库

utf8mb4_general_ci不区分大小写,ci:case insensitive缩写,
即大小写不敏感。

utf8mb4_general_cs区分大小写,cs:case sensitive的缩写,
即大小写敏感。

这里选择utf8mb4_bin

建库sql:

create database fruitMall DEFAULT CHARACTER set utf8mb4
COLLATE utf8mb4_bin

2.2 实体类编写

主程序类MainApplication和实体类entity位于同一包路径下:

springboot集成spring batch springboot集成spring jpa_spring


主程序类:

package com.xiaoxu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

/**
 * @author xiaoxu
 * @date 2022-03-26 12:48
 * FruitMall:PACKAGE_NAME.com.xiaoxu.MainApplication
 */
@SpringBootApplication
@ComponentScan(basePackages = {"com.xiaoxu"})
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class,args);
    }
}

实体类:

package com.xiaoxu.entity.Fruit;

import com.xiaoxu.entity.base.BaseTimeEntity;

import javax.persistence.*;
import java.math.BigDecimal;

/**
 * @author xiaoxu
 * @date 2022-03-26 13:01
 * FruitMall:com.xiaoxu.entity.Fruit.Fruit
 */
@Entity
//如果省略@Table(name = "my_fruit"),默认是对应的fruit表
@Table(name = "my_fruit")
public class Fruit extends BaseTimeEntity {
    /*
    * 水果ID
    * */
    //主键
    @Id
    //自增主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long fruitId;
    /*
    * 水果名称
    * */
    //和数据表对应的列,以及varchar的长度50
    @Column(name = "name",length = 50)
    private String name;
    /*
    * 水果单价
    * */
    // 省略,默认列名就是属性名
    @Column
    private BigDecimal unitPrice;
    /*
    * 水果划线价格(根据季节变动,价格进行浮动,可高可低可等)
    * */
    @Column(name = "cross_out_price")
    private BigDecimal crossOutPrice;
    /*
    * 水果单位质量
    * */
    @Column(name = "unit_weight")
    private int unitWeight;
    /*
    * 水果供销商ID
    * */
    private long supId;
    /*
    * 水果库存
    * */
    private long fruitStock;
    /*
    * 水果销量
    * */
    private long sales;
}

2.3 jpa配置文件编写

application.yml:

spring:
  banner:
    location:
      classpath:/banner/mybanner.txt
  datasource:
    username: root
    password: ******
	url: jdbc:mysql://localhost:3306/fruitmall?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      # 更新或者创建数据表
      ddl-auto: update
      # 控制台显式sql
      show-sql: true
#    properties:
#      hibernate:
#        dialect: org.hibernate.dialect.MySQL8Dialect

主程序类启动日志打印如下:

Using dialect: org.hibernate.dialect.MySQL8Dialect

可见,mysql8版本的,默认dialect也是使用的MySQL8Dialect。

2.4 建表

执行后,my_fruit表建表成功:

springboot集成spring batch springboot集成spring jpa_java_02


navicat查看对象信息ddl:

CREATE TABLE `my_fruit` (
  `fruit_id` bigint NOT NULL AUTO_INCREMENT,
  `cross_out_price` decimal(19,2) DEFAULT NULL,
  `fruit_stock` bigint NOT NULL,
  `name` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
  `sales` bigint NOT NULL,
  `sup_id` bigint NOT NULL,
  `unit_price` decimal(19,2) DEFAULT NULL,
  `unit_weight` int DEFAULT NULL,
  PRIMARY KEY (`fruit_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

1.fruit_id为主键,且不为null,为AUTO_INCREMENT自增id,long型为mysql中bigint类型;

2.name为String类型,即为mysql中的varchar类型,且长度为50;

3.cross_out_price为BigDecimal类型,对应mysql中的decimal(19,2)类型,默认金额保留到小数点后两位;

4.unit_weight是int类型,对应mysql中的int类型。

5.成员变量名均为小驼峰写法,JPA生成的数据库表的字段,转换后默认也是按照下划线来展示的。

2.5 继承类的字段

建表中,常常遇到重复且必须的字段,如创建时间、更新时间等字段,此时可以选择在抽象类中将公共数据表字段提取出来,然后使用@MappedSuperclass注解修饰抽象父类,此时所有继承该父类的@Entity子类,建表时会带上父类的表字段。

上述没有对Fruit的父类BaseTimeEntity中字段进行处理,处理方式如下:

springboot集成spring batch springboot集成spring jpa_spring_03


修改实体类如下:

BaseTimeEntity:

package com.xiaoxu.entity.base;

import javax.persistence.*;
import java.util.Date;

/**
 * @author xiaoxu
 * @date 2022-03-26 13:16
 * FruitMall:com.xiaoxu.entity.com.xiaoxu.base.BaseTimeEntity
 */

@MappedSuperclass
public abstract class BaseTimeEntity {
    /*
    * 创建时间
    * */
    Date createTime;

    /*
    * 更新时间
    * */
    Date modifyTime;

    /*
    * 额外信息
    * */
    String extraInfo;

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getModifyTime() {
        return modifyTime;
    }

    public void setModifyTime(Date modifyTime) {
        this.modifyTime = modifyTime;
    }

    public String getExtraInfo() {
        return extraInfo;
    }

    public void setExtraInfo(String extraInfo) {
        this.extraInfo = extraInfo;
    }
}

Fruit:

package com.xiaoxu.entity.Fruit;

import com.xiaoxu.entity.base.BaseTimeEntity;

import javax.persistence.*;
import java.math.BigDecimal;

/**
 * @author xiaoxu
 * @date 2022-03-26 13:01
 * FruitMall:com.xiaoxu.entity.Fruit.Fruit
 */
@Entity
//如果省略@Table(name = "my_fruit"),默认是对应的fruit表
@Table(name = "my_fruit")
public class Fruit extends BaseTimeEntity {
    /*
     * 水果ID
     * */
    //主键
    @Id
    //自增主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long fruitId;

    /*
     * 水果名称
     * */
    //和数据表对应的列,以及varchar的长度50
    @Column(name = "name",length = 50)
    private String name;

    /*
    * 水果单价
    * */
    // 省略,默认列名就是属性名
    @Column
    private BigDecimal unitPrice;

    /*
    * 水果划线价格(根据季节变动,价格进行浮动,可高可低可等)
    * */
    @Column(name = "cross_out_price")
    private BigDecimal crossOutPrice;

    /*
    * 水果单位质量
    * */
    @Column(name = "unit_weight")
    private int unitWeight;

    /*
    * 水果供销商ID
    * */
    private long supId;

    /*
    * 水果库存
    * */
    private long fruitStock;

    /*
    * 水果销量
    * */
    private long sales;
}

手动删除原先建的表,重新执行结果如下:

CREATE TABLE `my_fruit` (
  `fruit_id` bigint NOT NULL AUTO_INCREMENT,
  `create_time` datetime(6) DEFAULT NULL,
  `extra_info` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  `modify_time` datetime(6) DEFAULT NULL,
  `cross_out_price` decimal(19,2) DEFAULT NULL,
  `fruit_stock` bigint NOT NULL,
  `name` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,
  `sales` bigint NOT NULL,
  `sup_id` bigint NOT NULL,
  `unit_price` decimal(19,2) DEFAULT NULL,
  `unit_weight` int DEFAULT NULL,
  PRIMARY KEY (`fruit_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

由上述可知,my_fruit表建表时,自动带上了所继承的BaseTimeEntity父类的createTime、modifyTime、extraInfo字段。