【问题标题】:Something strange with mybatis and isnull on BigDecimal with Sybase在 Sybase 的 BigDecimal 上 mybatis 和 isnull 有点奇怪
【发布时间】:2017-02-23 08:20:18
【问题描述】:

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

我看到 mybatis update 总是返回 -1,并且 table 没有更新。

日志告诉我一些有趣的行为:
  • 创建新的 SqlSession
  • SqlSession [...] 未注册同步,因为同步未激活
  • JDBC 连接 [...] 不会由 Spring 管理
  • ==> 准备中:更新 Card set amount=isnull(?, amount), name=isnull(?, name), balanceTime=isnull(?, balanceTime) where number=?和 clientId=?。
  • ==> 参数:0.00(BigDecimal), Test Card(String), 2017-02-22 09:05:24.78(Timestamp), 0000000000000000(String), 111000(Long)
  • 关闭非事务性 SqlSession [...]

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

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

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

如果我将“金额”字段类型更改为 Double,一切正常。

如果我离开 BigDecimal 类型并将 "amount=isnull(#{card.amount}, amount)" 替换为 "amount=#{card.amount}" 或类似 "amount=isnull(0.00, amount)" 所有工作正常,在日志中我看到:

  • ==> 参数:0.0(BigDecimal), ....

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

【问题讨论】:

    标签: java mybatis bigdecimal isnull


    【解决方案1】:

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

    查看Mybatis default type handlers上的文档:

    使用 BigDecimal:

    BigDecimalTypeHandler java.math.BigDecimal 任何兼容的 数字或小数

    双:

    DoubleTypeHandler java.lang.Double, double 任何兼容 NUMERIC 或 DOUBLE

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

    即使在日志中,您会看到0.00(BigDecimal)0.00 只是 Java BigDecimal 的字符串表示形式,并且驱动程序实际绑定的值可能与 null 齐次,例如 0,有时@987654326 @ 而0!==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 个非空参数),&lt;set&gt; 必须包含(在最后一行)一些中性的东西(没有实际更新),例如:id=id

    【讨论】:

    • 感谢您的帮助!你对我的问题提出了一些好的想法。所以我为自己的问题创建了答案。
    【解决方案2】:

    我找到了我的问题的主要情况。在查看了 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://... b>”。 jConnect 驱动程序在更新时返回 1,而不是 jTDS 驱动程序返回 0

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-06
      • 2022-08-19
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 2021-08-27
      • 1970-01-01
      相关资源
      最近更新 更多