如何基于CSV创建JOOQ模拟数据库及绑定值异常排查
JOOQ Mock数据库CSV加载与INSERT异常解决
关于SQL绑定值的疑问
先明确一点:你看到的带?的SQL是预编译SQL语句,绑定值其实已经正确处理了——从你打印的getBindValues()和getParams()就能看出来,50331和1556686800已经和占位符关联上了。
你遇到的异常问题,核心不在绑定值,而是Mock环境的执行逻辑:JOOQ的MockConnection不会真的执行INSERT语句,而是完全依赖你在execute()方法里模拟的返回结果。你原来的代码返回了一个空的Result,JOOQ就会认为这次INSERT没有成功插入任何行,所以抛出了DataAccessException。
在Mock中添加CSV文件加载功能
你提到的CsvLoader返回Loader<Record>,其实只需要调用它的execute().result()就能拿到Result<Record>,刚好符合MockResult的需求。下面是调整后的完整代码,分场景处理不同SQL操作:
步骤1:提前加载CSV数据(避免重复IO)
可以在Mock类的初始化阶段加载CSV数据,这样每次执行查询时不用重复读取文件:
private final Result<MyTableRecord> csvData; public YourMockDataProvider(Configuration configuration) { DSLContext create = DSL.using(configuration); // 加载CSV文件到Result中 this.csvData = create.loadInto(MY_TABLE) .loadCSV(new File("your/csv/file/path.csv")) .fields(MY_TABLE.ID, MY_TABLE.EPOCH_TIME) // 指定CSV对应的表字段 .execute() .result(); }
步骤2:修改execute()方法,分SQL类型处理
@Override public MockResult[] execute(MockExecuteContext context) throws SQLException { String sql = context.sql().toLowerCase(); // 处理INSERT语句:模拟插入成功,返回受影响行数 if (sql.startsWith("insert into")) { // 这里的数字代表受影响行数,和你实际要插入的行数一致即可 return new MockResult[] { new MockResult(1, null) }; } // 处理SELECT语句:返回CSV加载的数据作为查询结果 if (sql.startsWith("select")) { return new MockResult[] { new MockResult(csvData.size(), csvData) }; } // 其他类型SQL(比如UPDATE/DELETE)可以按需添加模拟逻辑 return new MockResult[0]; }
关键说明
- INSERT操作:Mock不需要实际写入数据,只需要告诉JOOQ“这次插入影响了N行”即可,所以
MockResult的第二个参数传null(因为INSERT没有结果集)。 - SELECT操作:直接把提前加载好的CSV数据作为结果集返回,
MockResult的第一个参数是结果集的行数,第二个是结果集对象。 - CSV字段映射:确保
fields()方法指定的字段顺序和CSV文件的列顺序一致,避免数据错位。
这样修改后,你的INSERT操作会被Mock成成功执行,SELECT操作则会返回CSV里的模拟数据,解决之前的异常问题。
内容的提问来源于stack exchange,提问作者mitra
相关产品推荐
相关产品推荐

