mybatis批量插入BigDecimal精度丢失了(非批量没有问题)

西夏一品堂 发布于 2017/08/09 14:58
阅读 1K+
收藏 0

数据库为MSSQL2014

建表语句:

create table tb_test_user (id int not null identity, name nvarchar(50), balance decimal(19,5), interest decimal(19,5))

mapper.xml内容:

<mapper namespace="com.pp.jdbc.mapper.UserMapper">

	<insert id="batchInsert">
		INSERT INTO tb_test_user (name,balance,interest) VALUES
        <foreach collection="list" item="user" index="index" separator=",">
            (#{user.name},#{user.balance},#{user.interest})
        </foreach>
	</insert>
	
	<insert id="insert">
		INSERT INTO tb_test_user
        (name,balance,interest)
        VALUES
        (#{name},#{balance},#{interest})
	</insert>
	
</mapper>
public interface UserMapper {

	int insert(User user);
	
	int batchInsert(List<User> users);
}
import java.io.Serializable;
import java.math.BigDecimal;

import lombok.Data;

@Data
public class User implements Serializable {
	
	private static final long serialVersionUID = 1L;

	private Integer id;
	private String name;
	private BigDecimal balance;
	private BigDecimal interest;
	
	public User() {}
	
	public User(String name, double balance, double interest) {
		this.name = name;
		this.balance = BigDecimal.valueOf(balance);
		this.interest = BigDecimal.valueOf(interest);
	}
	
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", balance=" + balance + ", interest=" + interest + "]";
	}
}

调用

 

如果是调用批量的插入

public void save(UserMapper mapper) {
		List<User> users = new ArrayList<>();
    	users.add(new User("aa", 12d, 22d));
    	users.add(new User("bb", 12.1122d, 22.22333d));
    	users.add(new User("cc", 12.0d, 22.5d));
    	users.add(new User("dd", 12.5d, 22.2144d));
    	users.add(new User("ee", 12.7d, 22d));
    	users.add(new User("ff", 12.9874555d, 22.12341d));
    	mapper.batchInsert(users);
}

精度丢失了

 

但是,如果调用的是单个插入的方法,则没有问题

public void save(UserMapper mapper) {
		List<User> users = new ArrayList<>();
    	users.add(new User("aa", 12d, 22d));
    	users.add(new User("bb", 12.1122d, 22.22333d));
    	users.add(new User("cc", 12.0d, 22.5d));
    	users.add(new User("dd", 12.5d, 22.2144d));
    	users.add(new User("ee", 12.7d, 22d));
    	users.add(new User("ff", 12.9874555d, 22.12341d));
    	for(User user : users) {
    		mapper.insert(user);
    	}
}

 

请问,相同的代码,数据精度一样,为啥批量插入会有问题

 

 

 

加载中
0
DeMoNHaDeS
DeMoNHaDeS

User构造器已经丢失精度了。BigDecimal要使用String初始化。

DeMoNHaDeS
DeMoNHaDeS
回复 @西夏一品堂 : 没啥可说的,打印出来看看就知道了
西夏一品堂
西夏一品堂
看我下面的回复,使用BigDecimal.valueOf(balance);,把double转换成BigDecimal是没有问题的
DeMoNHaDeS
DeMoNHaDeS
回复 @西夏一品堂 : 你用double转String的时候就会出现精度问题,因此不要使用double。
西夏一品堂
西夏一品堂
回复 @DeMoNHaDeS : 规范的用法是?
DeMoNHaDeS
DeMoNHaDeS
回复 @西夏一品堂 : 跟批量非批量没有关系。这种用法是不规范的,因此不能保证是否会出现问题。而你在实际测试中非批量恰好没有出问题。你可以换成String试试。
下一页
0
Guest_Main
Guest_Main

指定参数类型试试 #{user.balance,jdbcType=DECIMAL,javaType=java.math.BigDecimal  }

Guest_Main
Guest_Main
回复 @西夏一品堂 : 你可以看mybatis org.apache.ibatis.builder.xml.XMLStatementBuilder 类parseStatementNode方法 SqlSource sqlSource 这行代码加个加个断点,看解析出来的参数类型
西夏一品堂
西夏一品堂
试过了,不行。我真正的问题是,为啥单个没有问题,批量有问题
0
北极心
北极心

直接字符串呗

0
混分丶小菜鸟
混分丶小菜鸟

既然是bigdecimal 为什么用double创建,不是mybatis的问题是你自己弄错了

0
混分丶小菜鸟
混分丶小菜鸟

double是因为不够精确,所以有时候会丢失数据精度,用bigdecimal重写下user构造函数就可以了

0
爱吃荷包蛋i
爱吃荷包蛋i

既然是bigdecimal 为什么用double创建??你的思路就有点问题  直接用string是最好的

 

0
西夏一品堂
西夏一品堂

看了大家的回复,大部分说是User构造函数有问题

this.balance = BigDecimal.valueOf(balance);
this.interest = BigDecimal.valueOf(interest);

说,这里是double转换成BigDecimal出了问题,实际上这里是没有问题的。BigDecimal.valueOf的源码为:

源码里面先把double转换成字符串,调用的是

Double.toString(val)

这句代码,是可以正常的把double转换成字符串,没有损失的。这里是没有问题的

 

综上所述,把double转换成BigDecimal的方法是没有问题的

0
Liuzh_533
Liuzh_533

使用你上面的代码,插入到mysql,没有任何问题。

另外我的getter和setter都是写好的,没用lombok.

西夏一品堂
西夏一品堂
难道是MSSQL的问题?
0
我的123

不要用#用$

西夏一品堂
西夏一品堂
为啥?$有SQL注入问题。另外,单条插入为啥没有问题
0
我的123

我终于找到原因了

返回顶部
顶部