序言
上篇講CRUD例子的時候講到每一次使用JOOQ都需要用到DSLContext的實例。
觀察上面圖片中的getAll()和updateUser()方法會發現,每次都用DSLContext的子類DSL的usring()方法來實例化DSLContext太麻煩。
能否定義一個DSLContext類型的成員變量,然后Dao中所有的方法都用這同一個DSLContext實例呢 ,答案是肯定的。
解決這個猜想的整個過程
想到這個問題,最開始想到的是既然需要一個DSLContext實例,那么去看看DSL.using()這個方法,打開DSL類的結構可以看到
using()方法有很多種實現,這里主要看需要Connection和DataSource參數的幾個using()方法。
因為想到Springboot中默認提供了Hikari數據庫連接池,和其他數據庫連接池一樣,它也有自己實現的DataSource。
想到這里,實例化DSLContext的所需要的參數都具備了,用代碼實現出來:
1 import org.jooq.Result; 2 import org.jooq.SQLDialect; 3 import org.jooq.impl.DSL; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Repository; 6 7 /** 8 * @author chaojizhengui 9 * @description user DAO 10 * @date 2020/5/15 14:52 11 */ 12 @Repository 13 public class UserDao { 14 // 注入Hikari的DataSource, 15 @Autowired 16 HikariDataSource dataSource; 17 18 // DSL上下文是所有數據庫操作的入口,意思就是要用jooq干任何事都要先實例化這個DSLContext 19 DSLContext create; 20 21 // 初始化DSLContext 22 public UserDao(){ 23 this.create = DSL.using(this.dataSource,SQLDialect.MYSQL); 24 } 25 26 /** 27 * 查詢 28 * @return 29 */ 30 public Result<BkUserRecord> getAll(){ 31 Result<BkUserRecord> result = this.create 32 .selectFrom(BkUser.BK_USER) 33 .orderBy(1) 34 .fetch(); 35 return result; 36 }
代碼有了,接下來就是測試,驗證自己的想法是否正確,在Springboot 的xxxxApplicationTests類中寫
測試方法:
//將userDao注入進單元測試類 @Autowired UserDao userDao; @Test void testUser(){ System.out.println("查詢---"); System.out.println(userDao.getAll()); System.out.println("查詢---"); }
執行結果:失敗
測試不通過,接下來就得去找找不通過的原因,給代碼加斷點跟蹤發現
仔細看上面的調試圖會發現,在UserDao的構造方法執行結束,dataSource都還是null,也就說明
1 @Autowired 2 HikariDataSource dataSource;
dataSource的通過@Autowired實例化的太晚了,需要通過其他的方式來為dataSource實例化。
所以聯想直接將@Autowired注解寫在構造函數上,就是直接在構造函數執行的時候就實例化dataSource。
將代碼改成:
1 package com.bkn.breakingnews.modules.user.dao; 2 3 import com.bkn.breakingnews.model.tables.BkUser; 4 import com.bkn.breakingnews.model.tables.records.BkUserRecord; 5 import com.zaxxer.hikari.HikariDataSource; 6 import org.jooq.DSLContext; 7 import org.jooq.Result; 8 import org.jooq.SQLDialect; 9 import org.jooq.impl.DSL; 10 import org.springframework.beans.factory.annotation.Autowired; 11 import org.springframework.stereotype.Repository; 12 13 /** 14 * @author chaojizhengui 15 * @description user DAO 16 * @date 2020/5/15 14:52 17 */ 18 @Repository 19 public class UserDao { 20 // DSL上下文是所有數據庫操作的入口,意思就是要用jooq干任何事都要先實例化這個DSLContext 21 DSLContext create; 22 // 初始化DSLContext,這里在構造器中注入Hikari的DataSource 23 @Autowired 24 public UserDao(HikariDataSource dataSource){ 25 this.create = DSL.using(dataSource,SQLDialect.MYSQL); 26 } 27 28 /** 29 * 查詢 30 * @return 31 */ 32 public Result<BkUserRecord> getAll(){ 33 Result<BkUserRecord> result = this.create 34 .selectFrom(BkUser.BK_USER) 35 .orderBy(1) 36 .fetch(); 37 return result; 38 }
測試結果:測試通過
優化之后每次就可以直接在方法中使用this.create直接來做SQL操作,免去每次都初始化DSLContext的麻煩。
這篇算是突然多出來的小插曲,其實和JOOQ的具體使用沒多大關系,記錄一下,猜想-解決問題-實現,的整個過程,希望有所收獲。
總結
a.以前用單元測試用的不多,每次有問題都是整個業務邏輯的代碼都跑一遍然后打斷點測試,這樣的調試方法雖然也可行,
但是沒有用單元測試看的直觀,多用單元測試會大大提高調試效率。
b.Bean的注入問題是Spring的核心之一,仍然需要多去理解。
Hikari