使用jOOQ DSL
本文是我們學院課程的一部分,標題為jOOQ –類型安全的數據庫查詢 。
在SQL和特定關系數據庫很重要的Java應用程序中,jOOQ是一個不錯的選擇。 當JPA / Hibernate抽象過多,JDBC過多時,這是一種替代方法。 它顯示了一種現代的領域特定語言如何可以極大地提高開發人員的生產率,從而將SQL內部化為Java。
在本課程中,我們將看到如何使用jOOQ有效地查詢數據庫。 在這里查看 !
目錄
1. jOOQ DSL的思想 2.運行第一個查詢 3.其他語句類型也可以從org.jooq.academy.section1包中獲得本節中顯示的示例 。
1. jOOQ DSL的思想
jOOQ是一種DSL(領域特定語言),它模仿Java API中的標準和特定于供應商的SQL語法。 該API背后的思想很容易理解:
- 作為內部 DSL,Java編譯器可以驗證您的SQL查詢的語法正確性(例如,SQL關鍵字的正確順序)
- 將表和列作為生成的Java對象,編譯器還可以驗證元數據的正確性(例如,正確的列名和類型)
換句話說,當您要表達這樣的SQL查詢時:
SELECT author.first_name, author.last_name FROM author ORDER BY author.id…然后您可以立即使用jOOQ編寫相同的查詢
select (AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from (AUTHOR) .orderBy(AUTHOR.ID);它是如何工作的,jOOQ和您的Java編譯器如何知道“ select ”的含義或“ AUTHOR.FIRST_NAME ”的含義?
2.運行第一個查詢
在上面的示例中,進行了兩個簡單的假設,并將在整個過程中進行以下假設:
- 每當您看到獨立的SQL關鍵字時,都可能是從org.jooq.impl.DSL靜態導入的。
- 每當您看到獨立的表引用時,它就可能是從生成的Tables類中靜態導入的
換句話說,理想情況下,在每個使用jOOQ的類中,只需添加以下兩個import語句:
import static org.jooq.example.db.h2.Tables.*; import static org.jooq.impl.DSL.*;這將使上面的代碼編譯。 但是,這樣的Select語句并不能做很多事情,它只是放在那兒,可以打印到控制臺上:
System.out.println(select (AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).from (AUTHOR).orderBy(AUTHOR.ID) );上面將打印:
select "PUBLIC"."AUTHOR"."FIRST_NAME", "PUBLIC"."AUTHOR"."LAST_NAME" from "PUBLIC"."AUTHOR" order by "PUBLIC"."AUTHOR"."ID" asc執行這樣的查詢非常簡單。 我們需要做的就是為其提供JDBC Connection ,然后在其上調用fetch() :
DSL.using(connection).select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).from(AUTHOR).orderBy(AUTHOR.ID).fetch();注意,當然,您也可以將對象分配給局部變量,或者使用Spring或您喜歡的配置框架來配置它,而不是一直重復DSL.using(...) :
DSLContext dsl = DSL.using(connection);dsl.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).from(AUTHOR).orderBy(AUTHOR.ID).fetch();jOOQ將在內部創建一個新的JDBC PreparedStatement ,執行它,使用JDBC ResultSet ,并急切地關閉它創建的所有資源。 結果對象是Result ,它也實現了一個非常有用的toString()方法:
System.out.println(dsl.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).from(AUTHOR).orderBy(AUTHOR.ID).fetch() );以上將產生:
+----------+---------+ |FIRST_NAME|LAST_NAME| +----------+---------+ |George |Orwell | |Paulo |Coelho | +----------+---------+3.其他語句類型
jOOQ本機支持每個DML SQL語句(以及一些DDL SQL語句),包括SELECT , UPDATE , INSERT , DELETE , MERGE 。 如果我們要創建,更新,刪除新的AUTHOR記錄,則可以編寫以下SQL語句:
插
dsl.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).values(3, "Alfred", "Hitchcock").execute();請注意,我們現在將調用execute()而不是fetch() execute() ,它返回受影響的行數。
上面查詢的一個有趣的方面是jOOQ使用很多Java泛型來確保查詢中的類型安全。 例如,以下兩個查詢將產生編譯錯誤:
dsl.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).values(3, "Alfred") // ^^^^^^^ values() expects three arguments (for ID, FIRST_NAME, LAST_NAME), // but only two were provided!.execute()這非常強大,因為您將永遠不會忘記根據INTO子句的要求向VALUES子句添加相等數量的值。 這也擴展到類型不匹配。 如果您決定對INTO子句中的列進行重新排序,但忘了改寫VALUES子句,則您的Java編譯器可能會再次抱怨。 以下內容無法編譯:
dsl.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, AUTHOR.ID).values(4, "Alfred", "Hitchcock") // ^^^^^^^ values() expects arguments of type (String, String, Integer),but (Integer, String, String) was provided!.execute()更新
UPDATE語句與前面的語句一樣簡單:
dsl.update(AUTHOR).set(AUTHOR.DATE_OF_BIRTH, Date.valueOf("1899-08-13")).where(AUTHOR.ID.eq(3)).execute()到目前為止,選擇ID = 3的作者將產生完整的AUTHOR記錄:
dsl.select().from(AUTHOR).where(AUTHOR.ID.eq(3)).fetch()……屈服
+----+----------+---------+-------------+ | ID|FIRST_NAME|LAST_NAME|DATE_OF_BIRTH| +----+----------+---------+-------------+ | 3|Alfred |Hitchcock|1899-08-13 | +----+----------+---------+-------------+刪除
最后但并非最不重要的一點是, DELETE語句如下:
dsl.delete(AUTHOR).where(AUTHOR.ID.eq(3)).execute()4.謂詞
謂詞是SQL(尤其是動態SQL)的重要方面。 SQL知道各種謂詞,例如:
日常謂詞
- 比較謂詞
- NULL謂詞
- 像謂詞
- IN謂詞
- 存在謂詞
更高級的謂詞
- 量化比較謂詞
- DISTINCT謂詞
- 謂詞之間
- 重疊謂詞
同樣,在SQL中,可以使用AND和OR輕松組合謂詞。 jOOQ以一種流利的方式直接在列類型上反映了所有這些謂詞。 最好通過示例解釋:
比較謂詞
// A filtering predicate AUTHOR.ID.eq(3);// A join predicate AUTHOR.ID.eq(BOOK.AUTHOR_ID);這些謂詞中的大多數也都是類型安全的,例如,您不能將數字與字符串進行比較。
AUTHOR.ID.eq("abc"); // ^^ Compilation error. An expression of type Integer is expected // (or Field<Integer>, or Select<? extends Record1<Integer>>)IN謂詞是類型安全的一個有趣案例,它需要一個值列表或一個在IN關鍵字右側僅包含一列的子查詢:
// IN list AUTHOR.ID.in(1, 2, 3);// IN with subquery AUTHOR.ID.in(select(BOOK.AUTHOR_ID).from(BOOK))第二個示例在AUTHOR表和BOOK表之間執行半AUTHOR ,僅返回至少寫過一本書的作者。 由于使用Java泛型,因此以下查詢將無法編譯:
// IN list with wrong types AUTHOR.ID.in("a", "b", "c"); // ^^^^^^^^^^^^^ This in() method expects an Integer... argument// IN with subquery returning wrong type AUTHOR.ID.in(select(BOOK.TITLE).from(BOOK)) // ^^^^^^^^^^^^^^^^^^ This in() method expects a Select<? extends Record1<Integer>> //另外,以下(無效)語句將被Java編譯器拒絕:
AUTHOR.ID.in(select(BOOK.AUTHOR_ID, BOOK.TITLE).from(BOOK)) // ^^ This in() method expects a Select<? extends Record1<Integer>>, // but instead, an incompatible Select<Record2<Integer, String>> was provided5.列表達式
在SQL中,您可以通過對列表達式應用函數或操作來創建新型的列表達式。 例如,您可以串聯作者的名字和姓氏:
在SQL中:
SELECT author.first_name || ' ' || author.last_name FROM author ORDER BY author.id使用jOOQ ::
dsl.select(concat(AUTHOR.FIRST_NAME, val(" "), AUTHOR.LAST_NAME)).from(AUTHOR).orderBy(AUTHOR.ID).fetch()請記住,我們是從DSL靜態導入所有內容,包括DSL.concat()和DSL.val() 。
dsl.select(AUTHOR.FIRST_NAME.concat(" ").concat(AUTHOR.LAST_NAME)).from(AUTHOR).orderBy(AUTHOR.ID).fetch()當然,由于Java不允許運算符重載(或符號方法名稱),因此我們必須處理常規方法名稱,在這種情況下,應使用concat 。 通常是由您決定要對函數使用前綴符號,還是對運算符使用前綴符號。
6.有關jOOQ DSL的更多信息
jOOQ DSL具有非常豐富的功能。 列出本課程中的所有功能將重復參考手冊。 請考慮手冊中有關SQL構建的部分,以了解有關jOOQ DSL的更多信息。
翻譯自: https://www.javacodegeeks.com/2015/09/work-with-the-jooq-dsl.html
總結
以上是生活随笔為你收集整理的使用jOOQ DSL的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java Concurrency Ess
- 下一篇: linux编码查看命令(linux编码查