javascript
jooq中record_在Spring中使用jOOQ:CRUD
jooq中record
jOOQ是一個庫,可幫助我們重新控制SQL。 它可以從我們的數據庫生成代碼,并允許我們使用其流暢的API來構建類型安全的數據庫查詢。
本教程前面的部分向我們介紹了如何配置示例應用程序的應用程序上下文以及如何從數據庫中生成代碼。
現在,我們準備向前邁出一步,學習如何使用jOOQ創建類型安全查詢。 這篇博客文章描述了如何將CRUD操作添加到管理待辦事項的簡單應用程序中。
讓我們開始吧。
補充閱讀:
- 將jOOQ與Spring結合使用:配置是本教程的第一部分,它描述了您可以配置使用jOOQ的Spring應用程序的應用程序上下文。 您可以在不閱讀本教程第一部分的情況下了解此博客文章,但是,如果您想在Spring支持的應用程序中真正使用jOOQ,建議您也閱讀本教程的第一部分。
- 將jOOQ與Spring結合使用:代碼生成是本教程的第二部分,它描述了如何對數據庫進行反向工程并創建代表不同數據庫表,記錄等的jOOQ查詢類。 因為這些類是類型安全SQL查詢的構建塊, 所以建議您在閱讀本博客文章之前閱讀本教程的第二部分 。
創建Todo類
讓我們從創建一個包含單個待辦事項條目信息的類開始。 此類具有以下字段:
- ID字段包含待辦事項的ID。
- creationTime字段包含一個時間戳,該時間戳描述了todo條目第一次被持久保存的時間。
- 描述字段包含待辦事項的描述。
- ModifyTime字段包含一個時間戳,該時間戳描述了待辦事項條目的更新時間。
- 標題字段包含待辦事項的標題。
這個相對簡單的類的名稱為Todo ,它遵循以下三個原則:
- 我們可以使用Joshua Bloch在Effective Java中描述的構建器模式來創建新的Todo對象。 如果您不熟悉此模式,則應閱讀標題為項目2的文章:面對許多構造函數參數時,請考慮使用構建器 。
- 標題字段是必填字段,我們不能創建標題為空或為空的新Todo對象。 如果我們嘗試創建標題無效的Todo對象,則會拋出IllegalStateException 。
- 此類是不可變的。 換句話說,其所有字段都聲明為final 。
Todo類的源代碼如下所示:
import org.apache.commons.lang3.builder.ToStringBuilder; import org.joda.time.LocalDateTime;import java.sql.Timestamp;public class Todo {private final Long id;private final LocalDateTime creationTime;private final String description;private final LocalDateTime modificationTime;private final String title;private Todo(Builder builder) {this.id = builder.id;LocalDateTime creationTime = null;if (builder.creationTime != null) {creationTime = new LocalDateTime(builder.creationTime);}this.creationTime = creationTime;this.description = builder.description;LocalDateTime modificationTime = null;if (builder.modificationTime != null) {modificationTime = new LocalDateTime(builder.modificationTime);}this.modificationTime = modificationTime;this.title = builder.title;}public static Builder getBuilder(String title) {return new Builder(title);}//Getters are omitted for the sake of clarity.public static class Builder {private Long id;private Timestamp creationTime;private String description;private Timestamp modificationTime;private String title;public Builder(String title) {this.title = title;}public Builder description(String description) {this.description = description;return this;}public Builder creationTime(Timestamp creationTime) {this.creationTime = creationTime;return this;}public Builder id(Long id) {this.id = id;return this;}public Builder modificationTime(Timestamp modificationTime) {this.modificationTime = modificationTime;return this;}public Todo build() {Todo created = new Todo(this);String title = created.getTitle();if (title == null || title.length() == 0) {throw new IllegalStateException("title cannot be null or empty");}return created;}} }讓我們找出為什么我們需要獲取當前日期和時間,更重要的是,什么是最好的方法。
獲取當前日期和時間
因為每個待辦事項的創建時間和修改時間都存儲在數據庫中,所以我們需要一種獲取當前日期和時間的方法。 當然,我們可以簡單地在存儲庫中創建此信息。 問題是,如果這樣做,我們將無法編寫自動測試來確保正確設置了創建時間和修改時間(我們無法為這些字段編寫斷言,因為它們的值取決于當前時間) 。
這就是為什么我們需要創建一個單獨的組件來負責返回當前日期和時間的原因。 DateTimeService接口聲明了以下兩種方法:
- getCurrentDateTime()方法將當前日期和時間作為LocalDateTime對象返回。
- getCurrentTimestamp()方法將當前日期和時間作為Timestamp對象返回。
DateTimeService接口的源代碼如下所示:
import org.joda.time.LocalDateTime; import java.sql.Timestamp;public interface DateTimeService {public LocalDateTime getCurrentDateTime();public Timestamp getCurrentTimestamp(); }因為我們的應用程序對“實時”感興趣,所以我們必須實現此接口并創建一個返回實際日期和時間的組件。 我們可以按照以下步驟進行操作:
CurrentTimeDateTimeService的源代碼如下所示:
import org.joda.time.LocalDateTime; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component;import java.sql.Timestamp;@Profile("application") @Component public class CurrentTimeDateTimeService implements DateTimeService {@Overridepublic LocalDateTime getCurrentDateTime() {return LocalDateTime.now();}@Overridepublic Timestamp getCurrentTimestamp() {return new Timestamp(System.currentTimeMillis());} }讓我們繼續并開始實現示例應用程序的存儲庫層。
實施存儲庫層
首先,我們創建一個存儲庫接口,該接口為待辦事項提供CRUD操作。 該接口聲明了以下五種方法:
- Todo add(Todo todoEntry)方法將新的todo條目保存到數據庫中,并返回保存的todo條目的信息。
- Todo delete(Long id)方法刪除一個待辦事項,并返回已刪除的待辦事項。
- List findAll()方法返回從數據庫中找到的所有待辦事項條目。
- Todo findById(Long id)返回單個todo條目的信息。
- Todo更新(Todo todoEntry)更新待辦事項的信息并返回更新后的待辦事項。
TodoRepository接口的源代碼如下所示:
import java.util.List;public interface TodoRepository {public Todo add(Todo todoEntry);public Todo delete(Long id);public List<Todo> findAll();public Todo findById(Long id);public Todo update(Todo todoEntry); }接下來,我們必須實現TodoRepository接口。 當我們這樣做時,我們必須遵循以下規則:
jOOQ創建的所有數據庫查詢都必須在事務內執行 。 這是因為我們的應用程序使用TransactionAwareDataSourceProxy類 ,并且如果我們在沒有事務的情況下執行數據庫查詢,則jOOQ將為每個操作使用不同的連接。 這可能會導致競賽條件錯誤。
通常,服務層充當事務邊界,并且對jOOQ存儲庫的每次調用都應在事務內部進行。 但是,由于程序員也會犯錯誤,因此我們不能相信情況就是如此。 這就是為什么我們必須使用@Transactional批注來批注存儲庫類或其方法。
既然已經了解了這一點,就可以創建存儲庫類了。
創建存儲庫類
我們可以按照以下步驟創建存儲庫類的“骨架”:
JOOQTodoRepository類的相關部分如下所示:
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord; import org.jooq.DSLContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository;@Repository public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;@Autowiredpublic JOOQTodoRepository(DateTimeService dateTimeService, DSLContext jooq) {this.dateTimeService = dateTimeService;this.jooq = jooq;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();} }讓我們繼續并實現為待辦事項提供CRUD操作的方法。
添加新的待辦事項
TodoRepository接口的公共Todo add(Todo todoEntry)方法用于向數據庫添加新的todo條目。 我們可以通過執行以下步驟來實現此方法:
JOOQTodoRepository類的相關部分如下所示:
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord; import org.jooq.DSLContext; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import java.sql.Timestamp;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional@Overridepublic Todo add(Todo todoEntry) {TodosRecord persisted = jooq.insertInto(TODOS).set(createRecord(todoEntry)).returning().fetchOne();return convertQueryResultToModelObject(persisted);}private TodosRecord createRecord(Todo todoEntry) {Timestamp currentTime = dateTimeService.getCurrentTimestamp();TodosRecord record = new TodosRecord();record.setCreationTime(currentTime);record.setDescription(todoEntry.getDescription());record.setModificationTime(currentTime);record.setTitle(todoEntry.getTitle());return record;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();} }4.3.3節。 jOOQ參考手冊的INSERT語句提供了有關將數據插入數據庫的其他信息。
讓我們繼續前進,找出如何找到存儲在數據庫中的所有條目。
查找所有待辦事項
TodoRepository接口的公共List findAll()方法返回所有存儲在數據庫中的待辦事項。 我們可以通過執行以下步驟來實現此方法:
JOOQTodoRepository類的相關部分如下所示:
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord; import org.jooq.DSLContext; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList; import java.util.List;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional(readOnly = true)@Overridepublic List<Todo> findAll() {List<Todo> todoEntries = new ArrayList<>();List<TodosRecord> queryResults = jooq.selectFrom(TODOS).fetchInto(TodosRecord.class);for (TodosRecord queryResult: queryResults) {Todo todoEntry = convertQueryResultToModelObject(queryResult);todoEntries.add(todoEntry);}return todoEntries;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();} }4.3.2節。 jOOQ參考手冊的SELECT語句提供了有關從數據庫中選擇信息的更多信息。
接下來,我們將找到如何從數據庫中獲得一個待辦事項。
查找單個待辦事項
TodoRepository接口的公共Todo findById(Long id)方法返回單個todo條目的信息。 我們可以通過執行以下步驟來實現此方法:
JOOQTodoRepository的相關部分如下所示:
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord; import org.jooq.DSLContext; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DSLContext jooq;//The constructor is omitted for the sake of clarity.@Transactional(readOnly = true)@Overridepublic Todo findById(Long id) {TodosRecord queryResult = jooq.selectFrom(TODOS).where(TODOS.ID.equal(id)).fetchOne();if (queryResult == null) {throw new TodoNotFoundException("No todo entry found with id: " + id);}return convertQueryResultToModelObject(queryResult);}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();} }4.3.2節。 jOOQ參考手冊的SELECT語句提供了有關從數據庫中選擇信息的更多信息。
讓我們找出如何從數據庫中刪除待辦事項。
刪除待辦事項
TodoRepository接口的公共Todo delete(Long id)方法用于從數據庫中刪除一個todo條目。 我們可以通過執行以下步驟來實現此方法:
JOOQTodoRepository類的相關部分如下所示:
import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord; import org.jooq.DSLContext; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional@Overridepublic Todo delete(Long id) {Todo deleted = findById(id);int deletedRecordCount = jooq.delete(TODOS).where(TODOS.ID.equal(id)).execute();return deleted;} }第4.3.5節。 jOOQ參考手冊的DELETE語句提供了有關從數據庫中刪除數據的其他信息。
讓我們繼續前進,找出如何更新現有待辦事項的信息。
更新現有的Todo條目
TodoRepository接口的公共Todo update(Todo todoEntry)方法將更新現有todo條目的信息。 我們可以通過執行以下步驟來實現此方法:
JOOQTodoRepository類的相關部分如下所示:
import org.jooq.DSLContext; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import java.sql.Timestamp;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;//The constructor is omitted for the sake of clarity.@Transactional@Overridepublic Todo update(Todo todoEntry) {Timestamp currentTime = dateTimeService.getCurrentTimestamp();int updatedRecordCount = jooq.update(TODOS).set(TODOS.DESCRIPTION, todoEntry.getDescription()).set(TODOS.MODIFICATION_TIME, currentTime).set(TODOS.TITLE, todoEntry.getTitle()).where(TODOS.ID.equal(todoEntry.getId())).execute();return findById(todoEntry.getId());} }- 第4.3.4節。 jOOQ參考手冊的UPDATE語句提供了有關更新存儲在數據庫中的信息的其他信息。
- 如果您使用的是Firebird或PostgreSQL數據庫,則可以在update語句中使用RETURNING子句 (并避免使用額外的select子句)。
就這些了。 讓我們總結一下我們從此博客文章中學到的知識。
摘要
現在,我們已經為待辦事項實現了CRUD操作。 本教程教會了我們三件事:
- 我們了解了如何以不妨礙我們為示例應用程序編寫自動測試的方式獲取當前日期和時間。
- 我們了解了如何確保jOOQ執行的所有數據庫查詢都在事務內執行。
- 我們學習了如何使用jOOQ API創建INSERT , SELECT , DELETE和UPDATE語句。
本教程的下一部分描述了如何向示例應用程序添加支持排序和分頁的搜索功能。
- 可以在Github上獲得此博客文章的示例應用程序(尚未實現前端)。
翻譯自: https://www.javacodegeeks.com/2014/04/using-jooq-with-spring-crud.html
jooq中record
總結
以上是生活随笔為你收集整理的jooq中record_在Spring中使用jOOQ:CRUD的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 竞价排名是什么意思 竞价排名解释
- 下一篇: 奇险天下第一山是哪座山 这座山挺拔峻峭