本文是我们学院课程的一部分,标题为jOOQ –类型安全的数据库查询 。
在SQL和特定关系数据库很重要的Java应用程序中,jOOQ是一个不错的选择。 当JPA / Hibernate抽象过多,JDBC过多时,这是一种替代方法。 它显示了一种现代的领域特定语言如何可以极大地提高开发人员的生产率,从而将SQL内部化为Java。
在本课程中,我们将看到如何使用jOOQ有效地查询数据库。 在这里查看 !
目录
- 1.简介 2.简单的活动记录操作 3.乐观锁
1.简介
虽然SQL是一种非常有表现力的语言,但是您的大多数SQL可能都是CRUD(创建,读取,更新,删除)。 编写这样的CRUD既无聊又重复,这就是为什么像Hibernate这样的ORM出现并成功提高开发人员生产力的原因。 但是,当您经常只想对表中的单个记录进行操作时,Hibernate对您的体系结构进行了许多假设(和限制)。
也可以从org.jooq.academy.section2包中获得本节中显示的示例 。
2.简单的活动记录操作
jOOQ知道“活动记录”或UpdatableRecords
,可以将其装入“特殊”种类的SELECT
语句,然后在内部跟踪脏标志。 这是在不编写过多SQL的DATE_OF_BIRTH
下更新作者DATE_OF_BIRTH
:
AuthorRecord author = dsl.selectFrom(AUTHOR).where(AUTHOR.ID.eq(1)).fetchOne();
author.setDateOfBirth(Date.valueOf("2000-01-01"));
author.store();
由于上面的示例仅通过selectFrom()
从一个表中进行选择,因此jOOQ知道结果记录类型将为AuthorRecord
,即由代码生成器生成的对象。 AuthorRecord
实现UpdatableRecord
,它具有多种有用的方法:
- store()
INSERT
或UPDATE
记录 - insert()
INSERT
记录 - update()
UPDATE
记录 - delete()
DELETE
记录 - refresh()从数据库刷新记录
以下示例部分将指导您完成创建,读取,更新,删除此类记录的整个生命周期:
AuthorRecord author;// Create a new record and store it to the database. This will perform an INSERT statement
author = dsl.newRecord(AUTHOR);
author.setId(3);
author.setFirstName("Alfred");
author.setLastName("Hitchcock");
author.store();// Read the record by refreshing it based on the primary key value
author = dsl.newRecord(AUTHOR);
author.setId(3);
author.refresh();// Update the record with a new value
author.setDateOfBirth(Date.valueOf("1899-08-13"));
author.store();// Delete the record again
author.delete();
jOOQ的UpdatableRecords
跟踪每列内部的“脏”或“已更改”状态,在调用store()
以便仅插入/更新已在UpdatableRecord
更改的值时使用该状态。
3.乐观锁
执行CRUD时,并发数据访问通常是一个可以通过两种方法解决的问题:
- 通过使用悲观锁定
- 通过使用乐观锁定
悲观锁定很少是一个好选择,因为当两个进程以不同的顺序锁定表中的几行以等待彼此完成时,死锁很容易发生。 乐观锁定是更合适的解决方案。 一个过程可能很幸运,可以在另一个过程尝试(失败)之前完成交易。 这是jOOQ的工作方式。
在我们的样本数据中, BOOK
表具有一个特殊的“系统”列,称为REC_TIMESTAMP
。 每当您在BookRecord
上运行CRUD操作时,jOOQ都会完全管理此列的内容,而不必保持最新状态。 考虑以下代码示例:
// Enable optimistic locking
DSLContext dsl = DSL.using(connection, new Settings().withExecuteWithOptimisticLocking(true));// Perform the CRUD with the above setting
BookRecord book1 = dsl.selectFrom(BOOK).where(BOOK.ID.eq(1)).fetchOne();
book1.setTitle("New Title");
book1.store();
jOOQ现在将执行一条UPDATE
语句,该语句还将更新并检查REC_TIMESTAMP
值:
update "PUBLIC"."BOOK"
set "PUBLIC"."BOOK"."TITLE" = 'New Title',"PUBLIC"."BOOK"."REC_TIMESTAMP" = timestamp '2014-09-08 18:40:39.416'
where ("PUBLIC"."BOOK"."ID" = 1 and "PUBLIC"."BOOK"."REC_TIMESTAMP" is null)
注意如何在SET
子句REC_TIMESTAMP
设置为当前时间,同时在WHERE
子句中还将其检查为NULL
(示例数据库中的初始值)。
如果我们现在有两个相互竞争的进程(或同一进程中的代码部分)进行此更新,如下所示:
BookRecord book1 = dsl.selectFrom(BOOK).where(BOOK.ID.eq(1)).fetchOne();
BookRecord book2 = dsl.selectFrom(BOOK).where(BOOK.ID.eq(1)).fetchOne();book1.setTitle("New Title");
book1.store();book2.setTitle("Another Title");
book2.store();
…然后,在对store()
的第二次调用(缩短的堆栈跟踪)上,我们将见证DataChangedException
:
org.jooq.exception.DataChangedException: Database record has been changed or doesn't exist any longerat org.jooq.impl.UpdatableRecordImpl.checkIfChanged(UpdatableRecordImpl.java:420)at org.jooq.impl.UpdatableRecordImpl.storeUpdate(UpdatableRecordImpl.java:193)at org.jooq.impl.UpdatableRecordImpl.store(UpdatableRecordImpl.java:129)at org.jooq.impl.UpdatableRecordImpl.store(UpdatableRecordImpl.java:121)
乐观锁定适用于UpdatableRecord
操作,包括insert()
, update()
和delete()
。
jOOQ支持三种乐观锁定模式:
- 使用专用的
TIMESTAMP
列来跟踪修改日期 - 使用专用的
NUMBER
列跟踪版本号 - 使用价值比较。 如果没有为代码生成器配置任何时间戳或版本列,则为默认设置
翻译自: https://www.javacodegeeks.com/2015/09/perform-crud-with-active-records.html