我使用Apache Derby作为内存模拟数据库,用于测试一些使用jOOQ与MySQL协同工作的代码。
生产数据库使用某些字段的枚举(这是这个问题的一个给定和超出范围 - 我知道枚举很糟糕但我现在无法更改此部分),因此jOOQ生成代码来处理枚举
不幸的是,Derby不支持枚举,当我尝试在Derby中创建数据库时(来自jOOQ SQL生成器),我收到错误。
我的解决方案是通过包装相关的jOOQ生成的枚举Java类来模仿枚举的用户定义类型。因此,例如,如果表kind
中有枚举字段stuffs
,则jOOQ SQL生成器会创建描述stuffs_kind
的Derby表创建SQL。
为了支持这一点,我创建了包含jOOQ生成的枚举类型my.project.tests.StuffsKindDebyEnum
的类my.project.model.StuffsKind
。然后,在运行jOOQ数据库创建SQL之前,我通过Derby运行以下SQL:
CREATE TYPE stuffs_kind EXTERNAL NAME 'my.project.tests.StuffsKindDerbyEnum' LANGUAGE JAVA
当我然后使用jOOQ插入新记录时,jOOQ会生成看起来像这样的SQL:
insert into "schema"."stuffs" ("text", "kind")
values (cast (? as varchar(32672)), cast(? as stuffs_kind)
但是将一个字符串值绑定到kind
参数(如预期的那样),它适用于MySQL但是使用Derby我得到一个例外:
java.sql.SQLDataException: An attempt was made to get a data value of type
'"APP"."STUFFS_KIND"' from a data value of type 'VARCHAR'
在查看解决此问题的各种方法之后(包括尝试将枚举视为简单的VARCHAR),在我放弃能够测试我的jOOQ使用代码之前,有没有办法让Derby进入& #34;铸造" varchar到用户定义的类型?如果可以放一些可以处理它的Java代码,那就不会有问题,因为我只需要StuffsKind.valueOf(value)
将字符串转换为正确的枚举类型,但在仔细阅读(非常小的)Derby文档后,我可以& #39;弄清楚它是否应该是可能的。
欢迎任何想法!
答案 0 :(得分:1)
这里正确的方法是使用方言敏感的自定义数据类型绑定: https://www.jooq.org/doc/latest/manual/sql-building/queryparts/custom-bindings
然后,绑定可以实现,例如绑定变量SQL生成如下:google.auth.scopes=https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me email profile
您显然还必须实现其他方法,告诉jOOQ如何将您的变量绑定到JDBC @Override
public void sql(BindingSQLContext<StuffsKindDerbyEnum> ctx) throws SQLException {
if (ctx.family() == MYSQL)
ctx.render().visit(DSL.val(ctx.convert(converter()).value()));
else if (ctx.family() == DERBY)
ctx.render()
.sql("cast(
.visit(DSL.val(ctx.convert(converter()).value()))
.sql(" as varchar(255))");
else
throw new UnsupportedOperationException("Dialect not supported: " + ctx.family());
}
,或者如何从PreparedStatement
另一种更简单的方法可能是避免特定于供应商的功能,只在两个数据库中使用ResultSet
。您仍然可以使用在两个数据库中以相同方式工作的jOOQ VARCHAR
将VARCHAR
映射到Java enum
类型。
更简单的方法是直接在MySQL上测试您的应用程序,例如:在内存中的docker虚拟化。数据库供应商和他们的功能之间存在很多差异,并且在某些时候,解决这些差异只是为了获得稍快的测试并不合理。
当然,例外情况是,如果您必须在生产中同时支持Derby和MySQL,那么数据类型绑定也是最佳解决方案。