【问题标题】:JDBI select on varbinary and uuidvarbinary 和 uuid 上的 JDBI 选择
【发布时间】:2021-09-02 02:03:18
【问题描述】:

旧的 mysql 数据库表有一个 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 选择它

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)
    }

}

我已经尝试了各种方法来使绑定工作但没有成功 - 任何建议都非常感谢!

【问题讨论】:

    标签: mysql varbinary jdbi jdbi3 jdbi3-core


    【解决方案1】:

    终于让它工作了,部分归功于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 参数在mysql以VARBINARY以外的东西结尾-例如,您可能有另一个表,其中您的JVM UUID实际上存储为VARCHAR或其他列,在这种情况下,您必须这样做,而不是在整个上注册UUID ArgumentFactory jdbi 实例,仅在适当的情况下对单个查询临时使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-26
      • 1970-01-01
      • 1970-01-01
      • 2018-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多