SpringBoot系列教程JPA之新增记录使用姿势

时间:2022-09-30 07:47:56

SpringBoot系列教程JPA之新增记录使用姿势

SpringBoot系列教程JPA之新增记录使用姿势

上一篇文章介绍了如何快速的搭建一个JPA的项目环境,并给出了一个简单的演示demo,接下来我们开始业务教程,也就是我们常说的CURD,接下来进入第一篇,如何添加数据

通过本篇文章,你可以get到以下技能点

  • POJO对象如何与表关联
  • 如何向DB中添加单条记录
  • 如何批量向DB中添加记录
  • save 与 saveAndFlush的区别

I. 环境准备

实际开始之前,需要先走一些必要的操作,如安装测试使用mysql,创建SpringBoot项目工程,设置好配置信息等,关于搭建项目的详情可以参考前一篇文章 190612-SpringBoot系列教程JPA之基础环境搭建

下面简单的看一下演示添加记录的过程中,需要的配置

1. 表准备

沿用前一篇的表,结构如下

CREATE TABLE `money` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
`money` int(26) NOT NULL DEFAULT '0' COMMENT '钱',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

2. 项目配置

配置信息,与之前有一点点区别,我们新增了更详细的日志打印;本篇主要目标集中在添加记录的使用姿势,对于配置说明,后面单独进行说明

## DataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=
## jpa相关配置
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

II. Insert使用教程

在开始之前,先声明一下,因为个人实际项目中并没有使用到JPA,对JPA的原则和hibernate的一些特性了解的也不多,目前处于学习探索阶段,主要是介绍下使用姿势,下面的东西都是经过测试得出,有些地方描述可能与规范不太一样,或者有些差错,请发现的大佬指正

接下来我们进入正题,如何通过JPA实现我们常见的Insert功能

1. POJO与表关联

首先第一步就是将POJO对象与表关联起来,这样就可以直接通过java的操作方式来实现数据库的操作了;

我们直接创建一个MoneyPo对象,包含上面表中的几个字段

@Data
public class MoneyPO {
private Integer id; private String name; private Long money; private Byte isDeleted; private Timestamp createAt; private Timestamp updateAt;
}

自然而然地,我们就有几个问题了

  • 这个POJO怎么告诉框架它是和表Money绑定的呢?
  • Java中变量命令推荐驼峰结构,那么 isDeleted 又如何与表中的 is_deleted 关联呢?
  • POJO中成员变量的类型如何与表中的保持一致呢,如果不一致会怎样呢?

针对上面的问题,一个一个来说明

对hibernate熟悉的同学,可能知道我可以通过xml配置的方式,来关联POJO与数据库表(当然mybatis也是这么玩的),友情链接一下hibernate的官方说明教程;我们使用SpringBoot,当然是选择注解的方式了,下面是通过注解的方式改造之后的DO对象

package com.git.hui.boot.jpa.entity;

import lombok.Data;
import org.springframework.data.annotation.CreatedDate; import javax.persistence.*;
import java.sql.Timestamp; /**
* Created by @author yihui in 21:01 19/6/10.
*/
@Data
@Entity(name="money")
public class MoneyPO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id; @Column(name = "name")
private String name; @Column(name = "money")
private Long money; @Column(name = "is_deleted")
private Byte isDeleted; @Column(name = "create_at")
@CreatedDate
private Timestamp createAt; @Column(name = "update_at")
@CreatedDate
private Timestamp updateAt;
}

有几个有意思的地方,需要我们注意

a. entity注解

@Entity 这个注解比较重要,用于声明这个POJO是一个与数据库中叫做 money 的表关联的对象;

  • @Entity注解有一个参数name,用于指定表名,如果不主动指定时,默认用类名,即上面如果不指定那么,那么默认与表 moneypo 绑定

另外一个常见的方式是在类上添加注解 @Table,然后指定表名,也是可以的

@Data
@Entity
@Table(name = "money")
public class MoneyPO {
}

b. 主键指定

我们可以看到id上面有三个注解,我们先看下前面两个

  • @Id 顾名思义,用来表明这家伙是主键,比较重要,需要特殊关照
  • @GeneratedValue 设置初始值,谈到主键,我们一般会和”自增“这个一起说,所以你经常会看到的取值为 strategy = GenerationType.IDENTITY (由数据库自动生成)

这个注解主要提供了四种方式,分别说明如下

取值 说明
GenerationType.TABLE 使用一个特定的数据库表格来保存主键
GenerationType.SEQUENCE 根据底层数据库的序列来生成主键,条件是数据库支持序列
GenerationType.IDENTITY 主键由数据库自动生成(主要是自动增长型)
GenerationType.AUTO 主键由程序控制

关于这几种使用姿势,这里不详细展开了,有兴趣的可以可以看一下这博文: @GeneratedValue

c. Column注解

这个注解就是用来解决我们pojo成员名和数据库列名不一致的问题的,这个注解内部的属性也不少,相对容易理解,后面会单开一章来记录这些常用注解的说明查阅

d. CreateDate注解

这个注解和前面不一样的是它并非来自jpa-api包,而是spring-data-common包中提供的,表示会根据当前时间创建一个时间戳对象

e. 其他

到这里这个POJO已经创建完毕,后续的表中添加记录也可以直接使用它了,但是还有几个问题是没有明确答案的,先提出来,期待后文可以给出回答

  1. POJO属性的类型与表中类型
  2. mysql表中列可以有默认值,这个在POJO中怎么体现
  3. 一个表包含另一个表的主键时(主键关联,外键)等特殊的情况,POJO中有体现么?

2. Repository API声明

jpa非常有意思的一点就是你只需要创建一个接口就可以实现db操作,就这么神奇,可惜本文里面见不到太多神奇的用法,这块放在查询篇来见证奇迹

我们定义的API需要继承自org.springframework.data.repository.CrudRepository,如下

package com.git.hui.boot.jpa.repository;

import com.git.hui.boot.jpa.entity.MoneyPO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository; /**
* 新增数据
* Created by @author yihui in 11:00 19/6/12.
*/
public interface MoneyCreateRepository extends CrudRepository<MoneyPO, Integer> {
}

好的,到这里就可以直接添加数据了 (感觉什么都没干,你居然告诉我可以插入数据???)

3. 使用姿势

a. 基础使用case

常规的使用姿势,无非单个插入和批量插入,我们先来看一下常规操作

@Component
public class JpaInsertDemo {
@Autowired
private MoneyCreateRepository moneyCreateRepository;
public void testInsert() {
addOne();
addMutl();
} private void addOne() {
// 单个添加
MoneyPO moneyPO = new MoneyPO();
moneyPO.setName("jpa 一灰灰");
moneyPO.setMoney(1000L);
moneyPO.setIsDeleted((byte) 0x00);
Timestamp now = new Timestamp(System.currentTimeMillis());
moneyPO.setCreateAt(now);
moneyPO.setUpdateAt(now); MoneyPO res = moneyCreateRepository.save(moneyPO);
System.out.println("after insert res: " + res);
} private void addMutl() {
// 批量添加
MoneyPO moneyPO = new MoneyPO();
moneyPO.setName("batch jpa 一灰灰");
moneyPO.setMoney(1000L);
moneyPO.setIsDeleted((byte) 0x00);
Timestamp now = new Timestamp(System.currentTimeMillis());
moneyPO.setCreateAt(now);
moneyPO.setUpdateAt(now); MoneyPO moneyPO2 = new MoneyPO();
moneyPO2.setName("batch jpa 一灰灰");
moneyPO2.setMoney(1000L);
moneyPO2.setIsDeleted((byte) 0x00);
moneyPO2.setCreateAt(now);
moneyPO2.setUpdateAt(now); Iterable<MoneyPO> res = moneyCreateRepository.saveAll(Arrays.asList(moneyPO, moneyPO2));
System.out.println("after batchAdd res: " + res);
}
}

看下上面的两个插入方式,就这么简单,

  • 通过IoC/DI注入 repository
  • 创建PO对象,然后调用save, saveAll方法就ok了

上面是一般的使用姿势,那么非一般使用姿势呢?

b. 插入时默认值支持方式

在创建表的时候,我们知道字段都有默认值,那么如果PO对象中某个成员我不传,可以插入成功么?会是默认的DB值么?

private void addWithNull() {
// 单个添加
try {
MoneyPO moneyPO = new MoneyPO();
moneyPO.setName("jpa 一灰灰 ex");
moneyPO.setMoney(2000L);
moneyPO.setIsDeleted(null);
MoneyPO res = moneyCreateRepository.save(moneyPO);
System.out.println("after insert res: " + res);
} catch (Exception e) {
System.out.println("addWithNull field: " + e.getMessage());
}
}

当看到上面的try/catch可能就有预感,上面的执行多半要跪(

SpringBoot系列教程JPA之新增记录使用姿势的更多相关文章

  1. SpringBoot系列教程JPA之指定id保存

    原文链接: 191119-SpringBoot系列教程JPA之指定id保存 前几天有位小伙伴问了一个很有意思的问题,使用 JPA 保存数据时,即便我指定了主键 id,但是新插入的数据主键却是 mysq ...

  2. SpringBoot 系列教程 JPA 错误姿势之环境配置问题

    191218-SpringBoot 系列教程 JPA 错误姿势之环境配置问题 又回到 jpa 的教程上了,这一篇源于某个简单的项目需要读写 db,本想着直接使用 jpa 会比较简单,然而悲催的是实际开 ...

  3. SpringBoot系列教程JPA之query使用姿势详解之基础篇

    前面的几篇文章分别介绍了CURD中的增删改,接下来进入最最常见的查询篇,看一下使用jpa进行db的记录查询时,可以怎么玩 本篇将介绍一些基础的查询使用姿势,主要包括根据字段查询,and/or/in/l ...

  4. SpringBoot 系列教程之编程式事务使用姿势介绍篇

    SpringBoot 系列教程之编程式事务使用姿势介绍篇 前面介绍的几篇事务的博文,主要是利用@Transactional注解的声明式使用姿势,其好处在于使用简单,侵入性低,可辨识性高(一看就知道使用 ...

  5. SpringBoot系列教程JPA之delete使用姿势详解

    原文: 190702-SpringBoot系列教程JPA之delete使用姿势详解 常见db中的四个操作curd,前面的几篇博文分别介绍了insert,update,接下来我们看下delete的使用姿 ...

  6. SpringBoot系列教程JPA之update使用姿势

    原文: 190623-SpringBoot系列教程JPA之update使用姿势 上面两篇博文拉开了jpa使用姿势的面纱一角,接下来我们继续往下扯,数据插入db之后,并不是说就一层不变了,就好比我在银行 ...

  7. SpringBoot系列教程JPA之基础环境搭建

    JPA(Java Persistence API)Java持久化API,是 Java 持久化的标准规范,Hibernate是持久化规范的技术实现,而Spring Data JPA是在 Hibernat ...

  8. SpringBoot 系列教程之事务隔离级别知识点小结

    SpringBoot 系列教程之事务隔离级别知识点小结 上一篇博文介绍了声明式事务@Transactional的简单使用姿势,最文章的最后给出了这个注解的多个属性,本文将着重放在事务隔离级别的知识点上 ...

  9. Java工程师之SpringBoot系列教程前言&amp&semi;目录

    前言 与时俱进是每一个程序员都应该有的意识,当一个Java程序员在当代步遍布的时候,你就行该想到我能多学点什么.可观的是后端的框架是稳定的,它们能够维持更久的时间在应用中,而不用担心技术的更新换代.但 ...

随机推荐

  1. DNS Prefetch

    DNS 实现域名到IP的映射.通过域名访问站点,每次请求都要做DNS解析.目前每次DNS解析,通常在200ms以下.针对DNS解析耗时问题,一些浏览器通过DNS Prefetch 来提高访问的流畅性. ...

  2. sql group by

    group by实例 实例一 数据表: 姓名 科目 分数 张三 语文 80 张三 数学 98 张三 英语 65 李四 语文 70 李四 数学 80 李四 英语 90 期望查询结果: 姓名 语文 数学 ...

  3. git各种撤销操作

    撤销git add: git reset HEAD+路径 或者git reset --+路径 撤销commit: 1.回退到具体的嘻哈值 git reset --hard     2.回退后仍包含本地 ...

  4. udt nat traverse

    https://github.com/bakwc/udt-nat-traverse Example of nat traversal using udt library. UDT is a udp b ...

  5. 【动态规划】流水作业调度问题与Johnson法则

    1.问题描述:     n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工.每个作业加工的顺序都是先在M1上加工,然后在M2上加工.M1和M2加工作业i所需的时间分别为ai和bi ...

  6. SDK文件夹下内容介绍

    Platform-Tools: 这是 adb, fastboot 等工具包.把解压出来的 platform-tools 文件夹放在 android sdk 根目录下,并把 adb所在的目录添加到系统 ...

  7. python中and和or的使用方法

    今天看了一个源代码,甚是对python不解,于是查了下资料,只是纠正下网上的老兄的解释 python 中的and从右到左计算表达式.若全部值均为真,则返回最后一个值.若存在假,返回第一个假值. or是 ...

  8. linux自动备份lampp的日志

    要求是:每天23:59自动备份lampp的日志/opt/lampp/logs/access_log 放到这个目录下/tmp/bak 命名格式:access_log.日期 1.新建shell脚本#vi ...

  9. VS2010 LNK1123&colon; 转换到 COFF 期间失败&colon; 文件无效或损坏

    1嵌入清单问题 属性: 项目\属性\配置属性\清单工具\输入和输出\嵌入清单:原来是“是”,改成“否”. 项目\属性\配置属性\链接器\清单文件\生成清单:原来是“是”,改成“否”. 2文件老旧: c ...

  10. 业务开发(一)—— MySQL

    0x01.SQL异常Incorrect string value java.sql.SQLException: Incorrect string value: '\xE6\x88\x91\xE7\x9 ...