javascript
jooq中record_在Spring中使用jOOQ:CRUD
jooq中record
jOOQ是一個(gè)庫(kù),可幫助我們重新控制SQL。 它可以從我們的數(shù)據(jù)庫(kù)生成代碼,并允許我們使用其流暢的API來(lái)構(gòu)建類(lèi)型安全的數(shù)據(jù)庫(kù)查詢(xún)。
本教程前面的部分向我們介紹了如何配置示例應(yīng)用程序的應(yīng)用程序上下文以及如何從數(shù)據(jù)庫(kù)中生成代碼。
現(xiàn)在,我們準(zhǔn)備向前邁出一步,學(xué)習(xí)如何使用jOOQ創(chuàng)建類(lèi)型安全查詢(xún)。 這篇博客文章描述了如何將CRUD操作添加到管理待辦事項(xiàng)的簡(jiǎn)單應(yīng)用程序中。
讓我們開(kāi)始吧。
補(bǔ)充閱讀:
- 將jOOQ與Spring結(jié)合使用:配置是本教程的第一部分,它描述了您可以配置使用jOOQ的Spring應(yīng)用程序的應(yīng)用程序上下文。 您可以在不閱讀本教程第一部分的情況下了解此博客文章,但是,如果您想在Spring支持的應(yīng)用程序中真正使用jOOQ,建議您也閱讀本教程的第一部分。
- 將jOOQ與Spring結(jié)合使用:代碼生成是本教程的第二部分,它描述了如何對(duì)數(shù)據(jù)庫(kù)進(jìn)行反向工程并創(chuàng)建代表不同數(shù)據(jù)庫(kù)表,記錄等的jOOQ查詢(xún)類(lèi)。 因?yàn)檫@些類(lèi)是類(lèi)型安全SQL查詢(xún)的構(gòu)建塊, 所以建議您在閱讀本博客文章之前閱讀本教程的第二部分 。
創(chuàng)建Todo類(lèi)
讓我們從創(chuàng)建一個(gè)包含單個(gè)待辦事項(xiàng)條目信息的類(lèi)開(kāi)始。 此類(lèi)具有以下字段:
- ID字段包含待辦事項(xiàng)的ID。
- creationTime字段包含一個(gè)時(shí)間戳,該時(shí)間戳描述了todo條目第一次被持久保存的時(shí)間。
- 描述字段包含待辦事項(xiàng)的描述。
- ModifyTime字段包含一個(gè)時(shí)間戳,該時(shí)間戳描述了待辦事項(xiàng)條目的更新時(shí)間。
- 標(biāo)題字段包含待辦事項(xiàng)的標(biāo)題。
這個(gè)相對(duì)簡(jiǎn)單的類(lèi)的名稱(chēng)為T(mén)odo ,它遵循以下三個(gè)原則:
- 我們可以使用Joshua Bloch在Effective Java中描述的構(gòu)建器模式來(lái)創(chuàng)建新的Todo對(duì)象。 如果您不熟悉此模式,則應(yīng)閱讀標(biāo)題為項(xiàng)目2的文章:面對(duì)許多構(gòu)造函數(shù)參數(shù)時(shí),請(qǐng)考慮使用構(gòu)建器 。
- 標(biāo)題字段是必填字段,我們不能創(chuàng)建標(biāo)題為空或?yàn)榭盏男耇odo對(duì)象。 如果我們嘗試創(chuàng)建標(biāo)題無(wú)效的Todo對(duì)象,則會(huì)拋出IllegalStateException 。
- 此類(lèi)是不可變的。 換句話(huà)說(shuō),其所有字段都聲明為final 。
Todo類(lèi)的源代碼如下所示:
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;}} }讓我們找出為什么我們需要獲取當(dāng)前日期和時(shí)間,更重要的是,什么是最好的方法。
獲取當(dāng)前日期和時(shí)間
因?yàn)槊總€(gè)待辦事項(xiàng)的創(chuàng)建時(shí)間和修改時(shí)間都存儲(chǔ)在數(shù)據(jù)庫(kù)中,所以我們需要一種獲取當(dāng)前日期和時(shí)間的方法。 當(dāng)然,我們可以簡(jiǎn)單地在存儲(chǔ)庫(kù)中創(chuàng)建此信息。 問(wèn)題是,如果這樣做,我們將無(wú)法編寫(xiě)自動(dòng)測(cè)試來(lái)確保正確設(shè)置了創(chuàng)建時(shí)間和修改時(shí)間(我們無(wú)法為這些字段編寫(xiě)斷言,因?yàn)樗鼈兊闹等Q于當(dāng)前時(shí)間) 。
這就是為什么我們需要?jiǎng)?chuàng)建一個(gè)單獨(dú)的組件來(lái)負(fù)責(zé)返回當(dāng)前日期和時(shí)間的原因。 DateTimeService接口聲明了以下兩種方法:
- getCurrentDateTime()方法將當(dāng)前日期和時(shí)間作為L(zhǎng)ocalDateTime對(duì)象返回。
- getCurrentTimestamp()方法將當(dāng)前日期和時(shí)間作為T(mén)imestamp對(duì)象返回。
DateTimeService接口的源代碼如下所示:
import org.joda.time.LocalDateTime; import java.sql.Timestamp;public interface DateTimeService {public LocalDateTime getCurrentDateTime();public Timestamp getCurrentTimestamp(); }因?yàn)槲覀兊膽?yīng)用程序?qū)Α皩?shí)時(shí)”感興趣,所以我們必須實(shí)現(xiàn)此接口并創(chuàng)建一個(gè)返回實(shí)際日期和時(shí)間的組件。 我們可以按照以下步驟進(jìn)行操作:
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());} }讓我們繼續(xù)并開(kāi)始實(shí)現(xiàn)示例應(yīng)用程序的存儲(chǔ)庫(kù)層。
實(shí)施存儲(chǔ)庫(kù)層
首先,我們創(chuàng)建一個(gè)存儲(chǔ)庫(kù)接口,該接口為待辦事項(xiàng)提供CRUD操作。 該接口聲明了以下五種方法:
- Todo add(Todo todoEntry)方法將新的todo條目保存到數(shù)據(jù)庫(kù)中,并返回保存的todo條目的信息。
- Todo delete(Long id)方法刪除一個(gè)待辦事項(xiàng),并返回已刪除的待辦事項(xiàng)。
- List findAll()方法返回從數(shù)據(jù)庫(kù)中找到的所有待辦事項(xiàng)條目。
- Todo findById(Long id)返回單個(gè)todo條目的信息。
- Todo更新(Todo todoEntry)更新待辦事項(xiàng)的信息并返回更新后的待辦事項(xiàng)。
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); }接下來(lái),我們必須實(shí)現(xiàn)TodoRepository接口。 當(dāng)我們這樣做時(shí),我們必須遵循以下規(guī)則:
jOOQ創(chuàng)建的所有數(shù)據(jù)庫(kù)查詢(xún)都必須在事務(wù)內(nèi)執(zhí)行 。 這是因?yàn)槲覀兊膽?yīng)用程序使用TransactionAwareDataSourceProxy類(lèi) ,并且如果我們?cè)跊](méi)有事務(wù)的情況下執(zhí)行數(shù)據(jù)庫(kù)查詢(xún),則jOOQ將為每個(gè)操作使用不同的連接。 這可能會(huì)導(dǎo)致競(jìng)賽條件錯(cuò)誤。
通常,服務(wù)層充當(dāng)事務(wù)邊界,并且對(duì)jOOQ存儲(chǔ)庫(kù)的每次調(diào)用都應(yīng)在事務(wù)內(nèi)部進(jìn)行。 但是,由于程序員也會(huì)犯錯(cuò)誤,因此我們不能相信情況就是如此。 這就是為什么我們必須使用@Transactional批注來(lái)批注存儲(chǔ)庫(kù)類(lèi)或其方法。
既然已經(jīng)了解了這一點(diǎn),就可以創(chuàng)建存儲(chǔ)庫(kù)類(lèi)了。
創(chuàng)建存儲(chǔ)庫(kù)類(lèi)
我們可以按照以下步驟創(chuàng)建存儲(chǔ)庫(kù)類(lèi)的“骨架”:
JOOQTodoRepository類(lèi)的相關(guān)部分如下所示:
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();} }讓我們繼續(xù)并實(shí)現(xiàn)為待辦事項(xiàng)提供CRUD操作的方法。
添加新的待辦事項(xiàng)
TodoRepository接口的公共Todo add(Todo todoEntry)方法用于向數(shù)據(jù)庫(kù)添加新的todo條目。 我們可以通過(guò)執(zhí)行以下步驟來(lái)實(shí)現(xiàn)此方法:
JOOQTodoRepository類(lèi)的相關(guān)部分如下所示:
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節(jié)。 jOOQ參考手冊(cè)的INSERT語(yǔ)句提供了有關(guān)將數(shù)據(jù)插入數(shù)據(jù)庫(kù)的其他信息。
讓我們繼續(xù)前進(jìn),找出如何找到存儲(chǔ)在數(shù)據(jù)庫(kù)中的所有條目。
查找所有待辦事項(xiàng)
TodoRepository接口的公共List findAll()方法返回所有存儲(chǔ)在數(shù)據(jù)庫(kù)中的待辦事項(xiàng)。 我們可以通過(guò)執(zhí)行以下步驟來(lái)實(shí)現(xiàn)此方法:
JOOQTodoRepository類(lèi)的相關(guān)部分如下所示:
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節(jié)。 jOOQ參考手冊(cè)的SELECT語(yǔ)句提供了有關(guān)從數(shù)據(jù)庫(kù)中選擇信息的更多信息。
接下來(lái),我們將找到如何從數(shù)據(jù)庫(kù)中獲得一個(gè)待辦事項(xiàng)。
查找單個(gè)待辦事項(xiàng)
TodoRepository接口的公共Todo findById(Long id)方法返回單個(gè)todo條目的信息。 我們可以通過(guò)執(zhí)行以下步驟來(lái)實(shí)現(xiàn)此方法:
JOOQTodoRepository的相關(guān)部分如下所示:
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節(jié)。 jOOQ參考手冊(cè)的SELECT語(yǔ)句提供了有關(guān)從數(shù)據(jù)庫(kù)中選擇信息的更多信息。
讓我們找出如何從數(shù)據(jù)庫(kù)中刪除待辦事項(xiàng)。
刪除待辦事項(xiàng)
TodoRepository接口的公共Todo delete(Long id)方法用于從數(shù)據(jù)庫(kù)中刪除一個(gè)todo條目。 我們可以通過(guò)執(zhí)行以下步驟來(lái)實(shí)現(xiàn)此方法:
JOOQTodoRepository類(lèi)的相關(guān)部分如下所示:
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節(jié)。 jOOQ參考手冊(cè)的DELETE語(yǔ)句提供了有關(guān)從數(shù)據(jù)庫(kù)中刪除數(shù)據(jù)的其他信息。
讓我們繼續(xù)前進(jìn),找出如何更新現(xiàn)有待辦事項(xiàng)的信息。
更新現(xiàn)有的Todo條目
TodoRepository接口的公共Todo update(Todo todoEntry)方法將更新現(xiàn)有todo條目的信息。 我們可以通過(guò)執(zhí)行以下步驟來(lái)實(shí)現(xiàn)此方法:
JOOQTodoRepository類(lèi)的相關(guān)部分如下所示:
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節(jié)。 jOOQ參考手冊(cè)的UPDATE語(yǔ)句提供了有關(guān)更新存儲(chǔ)在數(shù)據(jù)庫(kù)中的信息的其他信息。
- 如果您使用的是Firebird或PostgreSQL數(shù)據(jù)庫(kù),則可以在update語(yǔ)句中使用RETURNING子句 (并避免使用額外的select子句)。
就這些了。 讓我們總結(jié)一下我們從此博客文章中學(xué)到的知識(shí)。
摘要
現(xiàn)在,我們已經(jīng)為待辦事項(xiàng)實(shí)現(xiàn)了CRUD操作。 本教程教會(huì)了我們?nèi)?#xff1a;
- 我們了解了如何以不妨礙我們?yōu)槭纠龖?yīng)用程序編寫(xiě)自動(dòng)測(cè)試的方式獲取當(dāng)前日期和時(shí)間。
- 我們了解了如何確保jOOQ執(zhí)行的所有數(shù)據(jù)庫(kù)查詢(xún)都在事務(wù)內(nèi)執(zhí)行。
- 我們學(xué)習(xí)了如何使用jOOQ API創(chuàng)建INSERT , SELECT , DELETE和UPDATE語(yǔ)句。
本教程的下一部分描述了如何向示例應(yīng)用程序添加支持排序和分頁(yè)的搜索功能。
- 可以在Github上獲得此博客文章的示例應(yīng)用程序(尚未實(shí)現(xiàn)前端)。
翻譯自: https://www.javacodegeeks.com/2014/04/using-jooq-with-spring-crud.html
jooq中record
總結(jié)
以上是生活随笔為你收集整理的jooq中record_在Spring中使用jOOQ:CRUD的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 竞价排名是什么意思 竞价排名解释
- 下一篇: spring boot示例_Spring