Mybatis 有一些奇怪的东西,并且在 Sybase 的 BigDecimal 上是空的

Something strange with mybatis and isnull on BigDecimal with Sybase

几天前,我在添加新的接口实现后发现代码中出现了一些奇怪的行为。

我看到mybatis总是更新return-1,table没有更新

日志告诉我一些有趣的行为:

向服务器发送参数后没有任何反应。 这发生在我的 DAO 被重构之后:

public class DBaseCard{
    private long id;
    private String number;
    private String name;
    private BigDecimal amount; // was Double
    .....
}

在生产中我使用 Sybase IQ。对于测试,我使用 H2 db 并且一切正常。

如果我将 "amount" 字段类型更改为 Double,一切正常。

如果我保留 BigDecimal 类型并将 "amount=isnull(#{card.amount}, amount)" 替换为 "amount=#{card.amount}" 或 "amount=isnull(0.00, amount)" 之类的东西,一切正常,在日志中我看到:

请帮我理解为什么会这样。

这可能与 Sybase 中的列类型有关,H2 可能具有更宽松的行为。

查看 Mybatis default type handlers 上的文档:

使用 BigDecimal:

BigDecimalTypeHandler java.math.BigDecimal Any compatible NUMERIC or DECIMAL

加倍:

DoubleTypeHandler java.lang.Double, double Any compatible NUMERIC or DOUBLE

它可能来自 isnull 函数。您可以尝试替换为 coalesce.

即使在日志中,您看到 0.00(BigDecimal)0.00 只是 Java BigDecimal 的字符串表示形式,驱动程序实际绑定的值可能与 null 同质例如 0,有时 0==null0!==null,这可以解释为什么硬编码 0.00 按预期工作。

编写存储过程是一种选择。

你也可以考虑使用Mybatis dynamic SQL(trim,where,set)来构建SET,这样你就不用依赖在 isnull 上:

UPDATE
<set>
      <if test="amount!= null">amount=#{amount},</if>
      <if test="name!= null">name=#{name},</if>
      <if test="balanceTime!= null">balanceTime=#{balanceTime} </if>
</set>
WHERE number=#{number} AND clientId=#{clientId}

如果你不能保证 SET 中会有一些东西(至少 1 个不是空参数),<set> 必须包含(在最后一行)一些中性的东西(没有实际更新),比如:id=id.

我找到了我的问题的主要案例。在查看 mybatis 源代码一段时间后,我明白了,在我的情况下,Mybatis 或 SQL 本身没有任何内容。 SQL 从 ui 客户端请求工作,并且不能通过代码工作。我创建了一个简单的测试:

    Connection conn = DriverManager.getConnection("conn_string", "login", "pass");

    PreparedStatement ps = conn.prepareStatement("update Card set amount=isnull(?, amount), name=isnull(?, name), balanceTime=isnull(?, balanceTime) where number=? and clientId=?");

    //ps.setDouble(1, 12.23);
    ps.setBigDecimal(1, new BigDecimal("155.0"));
    ps.setString(2, "Test test");
    ps.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
    ps.setString(4, "00000000000000");
    ps.setLong(5, 111010111L);

    LOG.info("execute update result: {}", ps.executeUpdate());

    conn.close();

我为 'conn_string' 尝试了一些变体:“jdbc:jtds:sybase://...”和“ jdbc:sybase:Tds://...”。 jConnect 驱动程序 return 1 更新,而不是 jTDS 驱动程序 returns 0

看起来像 jTDS 驱动程序中的错误?