mybatis批量插入BigDecimal精度丢失了(非批量没有问题)
数据库为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);
}
}
请问,相同的代码,数据精度一样,为啥批量插入会有问题
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(19)
为啥?$有SQL注入问题。另外,单条插入为啥没有问题
我这边遇到和你相同的问题,你是怎么解决的?
不要用#用$
使用你上面的代码,插入到mysql,没有任何问题。
另外我的getter和setter都是写好的,没用lombok.
难道是MSSQL的问题?
看了大家的回复,大部分说是User构造函数有问题
this.balance = BigDecimal.valueOf(balance);
this.interest = BigDecimal.valueOf(interest);
说,这里是double转换成BigDecimal出了问题,实际上这里是没有问题的。BigDecimal.valueOf的源码为:
源码里面先把double转换成字符串,调用的是
Double.toString(val)
这句代码,是可以正常的把double转换成字符串,没有损失的。这里是没有问题的
综上所述,把double转换成BigDecimal的方法是没有问题的
既然是bigdecimal 为什么用double创建,不是mybatis的问题是你自己弄错了
double是因为不够精确,所以有时候会丢失数据精度,用bigdecimal重写下user构造函数就可以了
既然是bigdecimal 为什么用double创建??你的思路就有点问题 直接用string是最好的
试过了,不行。我真正的问题是,为啥单个没有问题,批量有问题
直接字符串呗
回复
你可以看mybatis org.apache.ibatis.builder.xml.XMLStatementBuilder 类parseStatementNode方法 SqlSource sqlSource 这行代码加个加个断点,看解析出来的参数类型
回复
跟批量非批量没有关系。这种用法是不规范的,因此不能保证是否会出现问题。而你在实际测试中非批量恰好没有出问题。你可以换成String试试。
指定参数类型试试 #{user.balance,jdbcType=DECIMAL,javaType=java.math.BigDecimal }
回复
规范的用法是?
回复
你用double转String的时候就会出现精度问题,因此不要使用double。
看我下面的回复,使用BigDecimal.valueOf(balance);,把double转换成BigDecimal是没有问题的
回复
没啥可说的,打印出来看看就知道了
User构造器已经丢失精度了。BigDecimal要使用String初始化。