Android SQLite插入float类型浮点数小数位数异常(四舍五入过的两位小数变成13位小数)的原因和解决方法

浮点数异常截图:

 说明:

正常保留两位小数并正确插入的记录是通过db.execSQL(sql);方法插入的,而浮点数异常的是通过ContentValues db.insert() 方式插入的,可以发现问题出在db.insert()方法上,我又试过在put的时候直接输入类似166.88存进去又是正常的。

查看db.insert源码:

    public long insertWithOnConflict(String table, String nullColumnHack,
            ContentValues initialValues, int conflictAlgorithm) {
        acquireReference();
        try {
            StringBuilder sql = new StringBuilder();
            sql.append("INSERT");
            sql.append(CONFLICT_VALUES[conflictAlgorithm]);
            sql.append(" INTO ");
            sql.append(table);
            sql.append('(');

            Object[] bindArgs = null;
            int size = (initialValues != null && !initialValues.isEmpty())
                    ? initialValues.size() : 0;
            if (size > 0) {
                bindArgs = new Object[size];
                int i = 0;
                for (String colName : initialValues.keySet()) {
                    sql.append((i > 0) ? "," : "");
                    sql.append(colName);
                    bindArgs[i++] = initialValues.get(colName);
                }
                sql.append(')');
                sql.append(" VALUES (");
                for (i = 0; i < size; i++) {
                    sql.append((i > 0) ? ",?" : "?");
                }
            } else {
                sql.append(nullColumnHack + ") VALUES (NULL");
            }
            sql.append(')');

            SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
            try {
                return statement.executeInsert();
            } finally {
                statement.close();
            }
        } finally {
            releaseReference();
        }
    }

可以看到是因为 put进去的float类型数据被内部做了数据类型转换. SQLiteDatabase的db.insert()方法会根据传入的值类型自动转换数据类型,可能会导致精度丢失的问题.

        ContentValues values = new ContentValues();
        //values.put("id", pay.getId());
        values.put("name", pay.getName());
        values.put("amount", pay.getAmount());
        values.put("real_amount", pay.getReal_amount());
        values.put("yh_amount", pay.getYh_amount());

如何解决这个问题:?

1,将字段类型改成String

2,使用db.execSQL(sql);方法拼接原生SQL插入

3,  在java代码中做转换,使用BigDecimal来转换保存。(麻烦)

4,  将Java中定义的金额类型由float改成double(首选)

5,  将SQLite中的金额字段类型改成Integer整数,然后按最小单位处理,比如8.56保存为856做位移(大部分人的做法)

我选择了第2种或第4种(视情况),用回最原始的拼接SQL直接执行的方式,安全靠谱简单。哈哈

db.insert()方法会根据传入的值类型自动转换数据类型,可能会导致精度丢失的问题。在SQLite中,float类型的数据只能存储约7位有效数字,如果插入的数据精度超过了这个范围,那么SQLite会自动将其截断或四舍五入,从而导致小数位数变长的现象。

如果你需要在SQLite中存储精度较高的数据,可以考虑使用REAL类型或NUMERIC类型,它们都可以存储高精度的数据。另外,为了避免精度丢失的问题,你可以将float类型改为double类型,这样就可以存储更多位的有效数字。

得出一个结论,java中能不用float数据类型就尽量不要用 

猜你喜欢

转载自blog.csdn.net/wh445306/article/details/130188175