【问题标题】:Hibernate and currency precision休眠和货币精度
【发布时间】:2008-12-30 02:42:03
【问题描述】:

我有一个休眠映射如下:

<hibernate-mapping>
    <class name="kochman.elie.data.types.InvoiceTVO" table="INVOICE">
        <id name="id" column="ID">
            <generator class="increment"/>
        </id>
        <property name="date" column="INVOICE_DATE"/>
        <property name="customerId" column="CUSTOMER_ID"/>
        <property name="schoolId" column="SCHOOL_ID"/>
        <property name="bookFee" column="BOOK_FEE"/>
        <property name="adminFee" column="ADMIN_FEE"/>
        <property name="totalFee" column="TOTAL_FEE"/>
    </class>
</hibernate-mapping>    

InvoiceTVO 的变量定义为:

private int id;
private Date date;
private int customerId;
private int schoolId;
private float bookFee;
private float adminFee;
private float totalFee;

当我在此表上执行插入操作时,出现以下错误:

Hibernate: insert into INVOICE (INVOICE_DATE, CUSTOMER_ID, SCHOOL_ID, BOOK_FEE, ADMIN_FEE, TOTAL_FEE, ID) values (?, ?, ?, ?, ?, ?, ?)
50156 [AWT-EventQueue-0] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 0, SQLState: 22001
50156 [AWT-EventQueue-0] ERROR org.hibernate.util.JDBCExceptionReporter - Data truncation: Data truncated for column 'ADMIN_FEE' at row 1
50156 [AWT-EventQueue-0] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session

我尝试将 adminFee 的类型更改为 double,但也没有用。问题是,Hibernate 实际上确实正确地执行了插入,并且未来的选择语句可以返回当前的值集,但是这个错误阻止了我对这张发票进行进一步的处理。

字段 bookFee、adminFee 和 totalFee 都应该是货币。它们在 MySQL 数据库中定义为十进制(5,2)。

对于如何解决此问题的任何帮助将不胜感激。

【问题讨论】:

  • 首先配置hibernate来显示实际的SQL查询。那会很有帮助。
  • 你是把它们定义为十进制 5,2 还是这个 Hibernate 做的?
  • 我做了,但是我继承了大部分数据,所以没有太多选择。
  • 那是“实际的 SQL 查询”,我将 Hibernate 设置为显示查询。据我所知,没有办法显示它实际使用的值。

标签: java hibernate types


【解决方案1】:

使用 float 或 double 来赚钱是绝对不可接受的,甚至可能是非法的(例如,违反法律或至少是法规)。这需要修复,然后错误就会消失。 float 精度有限,根本无法准确表示大多数小数。

For money, always, ALWAYS use BigDecimal.

【讨论】:

  • 如果您使用最基本的量化单位(例如,日元代表日本货币,美分代表美国),您可以完全避免使用分数。
  • 尝试使用 BigDecimal...我所有的数学都搞砸了,现在它只在所有字段中保存 0。
  • 哦,这个特定的应用程序没有任何法律问题,数字最后会四舍五入到下一个最大的整数,但他们希望准确保存。客户都知道这一点。
【解决方案2】:

我会使用整数类型(int、long)。只要您可以避免溢出,就永远不会出现任何有趣的问题。

【讨论】:

  • 不幸的是,美国财政部正在增加长期溢出的风险。
  • 实际上,它们更有可能出现长时间的下溢。
【解决方案3】:

您是否尝试过分配类型?

<property name="adminFee" column="ADMIN_FEE" type="float"/>

问题似乎在于数据的精度。有时当您有 1.26666666666... 时,该值会被截断。

您也可以在尝试插入之前尝试对其进行舍入。

见:http://bugs.mysql.com/bug.php?id=7829

另外,看看这是否有帮助: http://www.ibm.com/developerworks/java/library/j-jtp0114/

【讨论】:

    【解决方案4】:

    我最终没有使用 float、BigDecimal 或 double。我回到客户那里,他们同意放弃便士,因为无论如何向客户收取四舍五入的费用,所以没有必要存放便士。但是,我仍然需要弄清楚如何正确存储货币,因为这可能会再次出现。

    【讨论】:

      【解决方案5】:

      自定义 Hibernate 映射和类定义将是一个不错的选择。

      【讨论】:

      • 但是有哪些类型? Java 类型中 numeric(5,2) 映射到什么?
      猜你喜欢
      • 2013-07-26
      • 1970-01-01
      • 2021-11-22
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多