接下来我们开始进入 jooq 的增删改查的使用姿势系列,本篇将主要介绍如何利用 jooq 来实现添加数据
I. 项目搭建
本项目借助SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
进行开发
1. 项目依赖
关于如何创建一个 SpringBoot 的项目工程,不再本文的描述范围内,如有兴趣可以到文末的个人站点获取
在这个示例工程中,我们的选用 h2dabase 作为数据库(方便有兴趣的小伙伴直接获取工程源码之后,直接测试体验),因此对应的 pom 核心依赖如下
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jooq</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies> 复制代码
2. 数据库初始化
我们借助jooq-codegen-maven
插件来自动生成数据库相关的代码,对这一段逻辑感兴趣的小伙伴可以参考博文:【DB 系列】Jooq 代码自动生成
后文中使用的表结构如下
DROP TABLE IF EXISTS poet; CREATE TABLE poet ( `id` int NOT NULL, `name` varchar(20) NOT NULL default '', CONSTRAINT pk_t_poet PRIMARY KEY (ID) ); DROP TABLE IF EXISTS poetry; CREATE TABLE poetry ( `id` int NOT NULL, `poet_id` int NOT NULL default '0', `title` varchar(128) not null default '', `content` varchar(128) not null default '', CONSTRAINT pk_t_poetry PRIMARY KEY (ID) ); 复制代码
3. 配置文件
h2database 的连接配置如 application.properties
#Database Configuration spring.datasource.url=jdbc:h2:~/h2-jooq-poet spring.datasource.username=test spring.datasource.password= spring.datasource.driverClassName=org.h2.Driver #jOOQ Configuration spring.jooq.sql-dialect=H2 spring.datasource.initialization-mode=never spring.datasource.continueOnError=true ##h2 web console设置 spring.datasource.platform=h2 #进行该配置后,h2 web consloe就可以在远程访问了。否则只能在本机访问。 spring.h2.console.settings.web-allow-others=true #进行该配置,你就可以通过YOUR_URL/h2访问h2 web consloe spring.h2.console.path=/h2 #进行该配置,程序开启时就会启动h2 web consloe spring.h2.console.enabled=true 复制代码
II. 新增记录
接下来我们进入正式的数据插入的使用姿势介绍,一般来说新增数据会区分单个和批量两种方式,下面我们分别进行介绍
1. Record 实体类新增方式
在 jooq 中,借助自动生成的 Record 类来实现新增是最简单的 case,如下
private static final PoetTB table = PoetTB.POET; @Autowired private DSLContext dsl; /** * 新增记录 * * @param id * @param name * @return */ public boolean save(int id, String name) { PoetPO record = dsl.newRecord(table); record.setId(id); record.setName(name); return record.insert() > 0; } 复制代码
注意:
- 实体类的创建方式:
PoetPO record = dsl.newRecord(table);
,不要直接 new 一个对象出来使用
2. 链式写法
下面介绍的这种写法和 sql 非常相似,也是我个人用的比较多的方式,特点就是一目了然
public boolean save2(int id, String name) { return dsl.insertInto(table).set(table.ID, id).set(table.NAME, name).execute() > 0; } 复制代码
3. InsertQuery 方式
上面两种写法比较常见,而直接使用 InsertQuery 的方式,在实际的业务开发中可能并没有上面的优雅,但某些特殊场景下还是很有用的
/** * 不使用自动生成的代码来原生插入数据 * * @param id * @param name * @return */ public boolean save3(int id, String name) { // 当不使用自动生成的对象时,table可以用 DSL.table()指定,列可以用 DSL.field()指定 InsertQuery insertQuery = dsl.insertQuery(DSL.table("poet")); insertQuery.addValue(DSL.field("id", Integer.class), id); insertQuery.addValue(DSL.field("name", String.class), name); return insertQuery.execute() > 0; } 复制代码
注意一下上面的用法,InsertQuery
本身的使用没有什么值得说到的,重点在上面的实现中,并没有利用自动生成的代码,如
- table:
DSL.table(表名)
- field:
DSL.field(列名,类型)
通过上面的的 case,我们可以知道在不自动生成 DB 对应的代码前提下,如何进行数据库的操作
4. Record 实体批量保存
借助dsl.batchInsert
来批量添加实体,属于最基础的使用姿势了
private PoetPO bo2po(PoetBO bo) { PoetPO po = dsl.newRecord(table); po.setId(bo.getId()); po.setName(bo.getName()); return po; } /** * 通过Record执行批量添加 * * @param list * @return */ public boolean batchSave(List<PoetBO> list) { List<PoetPO> poList = list.stream().map(this::bo2po).collect(Collectors.toList()); int[] ans = dsl.batchInsert(poList).execute(); System.out.println(JSON.toJSONString(ans)); return true; } 复制代码
5. 链式批量保存
同样是类 sql 的链式插入方式,需要注意一下与前面的单条记录的链式插入的区别,下面这种写法和 sql 的批量插入的写法及其相似
/** * 类sql写法,批量添加 * * @param list * @return */ public boolean batchSave2(List<PoetBO> list) { InsertValuesStep2<PoetPO, Integer, String> step = dsl.insertInto(table).columns(table.ID, table.NAME); for (PoetBO bo : list) { step.values(bo.getId(), bo.getName()); } return step.execute() > 0; } 复制代码
6. InsertQuery 批量保存
上面介绍了 InsetQuery 的单条插入方式,下面的批量写法基本上没有太大的区别
/** * 不基于自动生成的代码,来批量添加数据 * * @param list * @return */ public boolean batchSave3(List<PoetBO> list) { InsertQuery insertQuery = dsl.insertQuery(DSL.table("poet")); for (PoetBO bo : list) { insertQuery.addValue(DSL.field("id", Integer.class), bo.getId()); insertQuery.addValue(DSL.field("name", String.class), bo.getName()); insertQuery.newRecord(); } return insertQuery.execute() > 0; } 复制代码
7. 测试 case
接下来测试一下上面的 6 个方法执行
public void test() { this.save(11, "一灰"); this.save2(12, "一灰灰"); this.save3(13, "一灰灰Blog"); this.batchSave(Arrays.asList(new PoetBO(14, "yh"), new PoetBO(15, "yhh"))); this.batchSave2(Arrays.asList(new PoetBO(16, "yihui"), new PoetBO(17, "yihuihui"))); this.batchSave3(Arrays.asList(new PoetBO(18, "YiHui"), new PoetBO(19, "YiHuiBlog"))); RecordMapper<PoetPO, PoetBO> mapper = dsl.configuration().recordMapperProvider().provide(table.recordType(), PoetBO.class); List<PoetBO> result = dsl.selectFrom(table).fetch().map(mapper); System.out.println(result); } 复制代码
输出结果如下
[1,1] [PoetBO (1, 李白), PoetBO (2, 艾可翁), PoetBO (11, 一灰), PoetBO (12, 一灰灰), PoetBO (13, 一灰灰Blog), Po