序言
上篇讲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