《你不知道的 JAVA》博客系列 🔥 掌握数据库 Simple CRUD 的秘诀

书接上文

自从上一篇 Blog 发出以后,有佬友提出了这样一种观点:「我管你这那的,数据库我只用增删改查,连分页都不用一样能写程序」。

这篇文章不讨论这种做法的对错,只介绍 JOOQ 针对这种使用方式的解决方案。

Simple CRUD

上述的使用方式在数据库操作中有个专业名词,叫做 Simple CRUD。这不是什么神奇的功能,大多数数据操作库都会提供这个功能的解决方案。当然,原始的 Mybatis 没有这个功能——所以我们常说:Mybatis 是一个上古时代的框架。

言归正传,对于这样一个 SQL 来说,Mybatis Plus 和 JOOQ 中的 Simple CRUD 分别如下所示:

SELECT * FROM user WHERE username = 'John';

Mybatis Plus

public interface UserMapper extends BaseMapper<User> {
    
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
   
}

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", "John");

List<User> userList = userMapper.selectList(queryWrapper);

JOOQ

@Autowired private DSLContext dsl;

List<User> users = dsl.selectFrom(USER).where(USER.USERNAME.eq("John")).fetchInto(User.class);

DSLContext 是什么

JOOQ 不需要什么额外的样板代码,DSLContext 就是 JOOQ 和数据库交互的核心 API——当和 SpringBoot 进行集成时,通过 @Autowired private DSLContext dsl便可在任意地方注入进行使用,就算你在 Controller 里面用也可以。

Q:有好事者问了,那我不用 SpringBoot,使用 JOOQ 还像这样方便吗?
A:是的,那更方便了。

DSL.selectFrom(USER).fetch()

查询数据

上面我们已经介绍过了,除此之外还能使用 fetchOne 等其他变体。

User user = dsl.selectFrom(USER).fetchOne();

插入数据

通过 newRecord 创建的对象叫做 UpdatableRecords,这是一个隐含了数据库链接的对象,store 就是插入数据的方法。

UserRecord userRecord = dsl.newRecord(USER);
userRecord.setUsername("[email protected]");
userRecord.setPassword("falr2b9nCVY5hS1o");
userRecord.store();

更新数据

store 是一个 upsert 操作,它不仅能够插入数据,还能够更新数据。这是全自动的,当对象在数据库里已经存在时,再调用 store 就是更新操作。

// 插入新数据
UserRecord userRecord = dsl.newRecord(USER);
userRecord.setUsername("[email protected]");
userRecord.setPassword("falr2b9nCVY5hS1o");
userRecord.store();
// userRecord 插入完毕后再次调用 store 则自动更新
userRecord.setPassword("JHMDoQPKuEcgILE6");
userRecord.store();

删除数据

UserRecord userRecord = dsl.fetchOne(USER, USER.USERNAME.eq("testUserA"));
userRecord.delete();

刷新数据

一个被查询出的UpdatableRecords 代表的数据库状态可能不是最新的,因为别的线程可能在你之后改变了数据库状态。调用 refresh 可以刷新对象的属性为数据库的最新状态。

// 线程A
UserRecord fetchedOne = dsl.fetchOne(USER, USER.USERNAME.eq("[email protected]"));
assertThat(fetchedOne.getPassword()).isEqualTo("falr2b9nCVY5hS1o");

// 线程B
userRecord.setPassword("JHMDoQPKuEcgILE6");
userRecord.store();

// 线程A
fetchedOne.refresh();
assertThat(fetchedOne.getPassword()).isEqualTo("JHMDoQPKuEcgILE6");

致其他语言的开发者

虽然 JOOQ 不是一个 ORM(Mybatis 当然更不是),但是对于使用 C# 和 PHP 及 Ruby 的开发者来说,当你在项目中不得不使用 Java 时,JOOQ 会不会稍微让你对这个领域的 CRUD 生态提起一点点信心?

写在最后

我是 Chuck1sn,一个长期致力于现代 Jvm 生态推广的开发者。您的回帖、点赞、收藏、就是我持续更新的动力;举手之劳的一键三连对我来说是莫大的支持,非常感谢!还可关注我的账号,第一时间收到文章推送。

26 个赞

本篇文章加上一篇文章基本涵盖了使用 JOOQ 进行 CRUD 的 80% 的功能,所以其使用成本和配置成本都非常的低。

1 个赞

棒!干到了

2 个赞

这玩意不是active record?

3 个赞

我用jdbcTemplate

3 个赞

感谢大佬教程

2 个赞

干杯。 :partying_face:

3 个赞

这个支持动态数据源吗?或多个数据源

3 个赞

这个肯定支持的,这些都是基本功能。
如果有两个数据源,对应就有两个不同的 DSLContext,想用哪个就注入哪个。

3 个赞

是的,文中提到的就是类 ORM 的 API

3 个赞

是的,这个跟 hibernate 的 active record 很像。官网上也是说这是类 ORM写法。不过像这种非 ORM 框架肯定不会去实现所有的 ORM 特性,只能说提供一个基础的解决方案。

3 个赞

谢谢大帅哥。

3 个赞

大佬,给几个JOOQ和shardingJDBC结合使用的例子吧

5 个赞

这一块儿我确实没接触过,要不你搜一下看看,这个框架存在时间挺久了,只要不是太非主流的东西应该都支持。

2 个赞

Jdbc Template 我以前也用,比较轻量级。后来用了 JOOQ 后反正这个也挺方便就统一用 JOOQ 了。

SIMPLE CRUD 这种 api 用起来感觉和 ORM 有点像,但是这个不是ORM,也无法提供关系的表达。只是一个单表操作的指南。


我帮你搜了一下,虽然 shardingJDBC 我没有用过,但是 JOOQ 可以直接通过 DSLContext 直接访问到 Connection 接口。

不知道这个对你用 shardingJDBC 有没有帮助?按理来说 shardingJDBC 应该是内部做了抽象的,暴露出的应该还是 Connection 之类的接口。

1 个赞

比 mybatis plus 爽多了,支持期待后面有更多的解决方案 给开发者带来更好的体验

1 个赞

谢谢佬友支持,可以关注我的账号,后面我发送的时候可以收到推送。

1 个赞