JDBI select 关于 varbinary 和 uuid
JDBI select on varbinary and uuid
遗留 mysql db table 有一个 id 列,它是非人类可读的原始 varbinary(不要问我为什么 :P)
CREATE TABLE IF NOT EXISTS `tbl_portfolio` (
`id` varbinary(16) NOT NULL,
`name` varchar(128) NOT NULL,
...
PRIMARY KEY (`id`)
);
我需要根据 java.util.UUID
select
jdbiReader
.withHandle<PortfolioData, JdbiException> { handle ->
handle
.createQuery(
"""
SELECT *
FROM tbl_portfolio
WHERE id = :id
"""
)
.bind("id", uuid) //mapping this uuid into the varbinary
//id db column is the problem
.mapTo(PortfolioData::class.java) //the mapper out does work
.firstOrNull()
}
为了以防万一有人想看到它,这里是映射器输出(但同样,映射器输出不是问题 - 将 uuid 绑定到 varbinary id db 列)
class PortfolioDataMapper : RowMapper<PortfolioData> {
override fun map(
rs: ResultSet,
ctx: StatementContext
): PortfolioData = PortfolioData(
fromBytes(rs.getBytes("id")),
rs.getString("name"),
rs.getString("portfolio_idempotent_key")
)
private fun fromBytes(bytes: ByteArray): UUID {
val byteBuff = ByteBuffer.wrap(bytes)
val first = byteBuff.long
val second = byteBuff.long
return UUID(first, second)
}
}
我已经尝试了各种方法来使绑定工作但没有成功 - 非常感谢任何建议!
终于让它工作了,部分归功于 https://jdbi.org/#_argumentfactory,它实际上专门处理 UUID,但尽管我看了几个小时的 JDBI 文档,但我不知何故还是错过了,哦,好吧
查询可以保持这样
jdbiReader
.withHandle<PortfolioData, JdbiException> { handle ->
handle
.createQuery(
"""
SELECT *
FROM tbl_portfolio
WHERE id = :id
"""
)
.bind("id", uuid)
.mapTo(PortfolioData::class.java)
.firstOrNull()
}
但是jdbi需要注册一个UUIDArgumentFactory
jdbi.registerArgument(UUIDArgumentFactory(VARBINARY))
哪里
class UUIDArgumentFactory(sqlType: Int) : AbstractArgumentFactory<UUID>(sqlType) {
override fun build(
value: UUID,
config: ConfigRegistry?
): Argument {
return UUIDArgument(value)
}
}
哪里
class UUIDArgument(private val value: UUID) : Argument {
companion object {
private const val UUID_SIZE = 16
}
@Throws(SQLException::class)
override fun apply(
position: Int,
statement: PreparedStatement,
ctx: StatementContext
) {
val bb = ByteBuffer.wrap(ByteArray(UUID_SIZE))
bb.putLong(value.mostSignificantBits)
bb.putLong(value.leastSignificantBits)
statement.setBytes(position, bb.array())
}
}
注意,像这样在整个 jdbi 实例上注册一个 ArgumentFactory 会使发送到 .bind 的所有 UUID 类型参数映射到字节,这可能不是你想要的,以防你的代码库中的其他地方有其他 UUID 参数以 VARBINARY 以外的其他内容存储在 mysql 端 - 例如,您可能有另一个 table 带有一列,其中您的 JVM UUID 实际上存储为 VARCHAR 或其他任何内容,在这种情况下您必须,而不是在整个 jdbi 实例上注册 UUID ArgumentFactory,只在适当的地方临时使用它。
遗留 mysql db table 有一个 id 列,它是非人类可读的原始 varbinary(不要问我为什么 :P)
CREATE TABLE IF NOT EXISTS `tbl_portfolio` (
`id` varbinary(16) NOT NULL,
`name` varchar(128) NOT NULL,
...
PRIMARY KEY (`id`)
);
我需要根据 java.util.UUID
selectjdbiReader
.withHandle<PortfolioData, JdbiException> { handle ->
handle
.createQuery(
"""
SELECT *
FROM tbl_portfolio
WHERE id = :id
"""
)
.bind("id", uuid) //mapping this uuid into the varbinary
//id db column is the problem
.mapTo(PortfolioData::class.java) //the mapper out does work
.firstOrNull()
}
为了以防万一有人想看到它,这里是映射器输出(但同样,映射器输出不是问题 - 将 uuid 绑定到 varbinary id db 列)
class PortfolioDataMapper : RowMapper<PortfolioData> {
override fun map(
rs: ResultSet,
ctx: StatementContext
): PortfolioData = PortfolioData(
fromBytes(rs.getBytes("id")),
rs.getString("name"),
rs.getString("portfolio_idempotent_key")
)
private fun fromBytes(bytes: ByteArray): UUID {
val byteBuff = ByteBuffer.wrap(bytes)
val first = byteBuff.long
val second = byteBuff.long
return UUID(first, second)
}
}
我已经尝试了各种方法来使绑定工作但没有成功 - 非常感谢任何建议!
终于让它工作了,部分归功于 https://jdbi.org/#_argumentfactory,它实际上专门处理 UUID,但尽管我看了几个小时的 JDBI 文档,但我不知何故还是错过了,哦,好吧
查询可以保持这样
jdbiReader
.withHandle<PortfolioData, JdbiException> { handle ->
handle
.createQuery(
"""
SELECT *
FROM tbl_portfolio
WHERE id = :id
"""
)
.bind("id", uuid)
.mapTo(PortfolioData::class.java)
.firstOrNull()
}
但是jdbi需要注册一个UUIDArgumentFactory
jdbi.registerArgument(UUIDArgumentFactory(VARBINARY))
哪里
class UUIDArgumentFactory(sqlType: Int) : AbstractArgumentFactory<UUID>(sqlType) {
override fun build(
value: UUID,
config: ConfigRegistry?
): Argument {
return UUIDArgument(value)
}
}
哪里
class UUIDArgument(private val value: UUID) : Argument {
companion object {
private const val UUID_SIZE = 16
}
@Throws(SQLException::class)
override fun apply(
position: Int,
statement: PreparedStatement,
ctx: StatementContext
) {
val bb = ByteBuffer.wrap(ByteArray(UUID_SIZE))
bb.putLong(value.mostSignificantBits)
bb.putLong(value.leastSignificantBits)
statement.setBytes(position, bb.array())
}
}
注意,像这样在整个 jdbi 实例上注册一个 ArgumentFactory 会使发送到 .bind 的所有 UUID 类型参数映射到字节,这可能不是你想要的,以防你的代码库中的其他地方有其他 UUID 参数以 VARBINARY 以外的其他内容存储在 mysql 端 - 例如,您可能有另一个 table 带有一列,其中您的 JVM UUID 实际上存储为 VARCHAR 或其他任何内容,在这种情况下您必须,而不是在整个 jdbi 实例上注册 UUID ArgumentFactory,只在适当的地方临时使用它。