首页 新闻 会员 周边 捐助

关于使用foreach迭代器批量insert数据失败的问题

0
悬赏园豆:100 [已解决问题] 解决于 2023-06-16 17:05

项目有一个简单的批量插入,一开始本地使用的迭代器,循环调用insert接口,
list.foreach(x -> basemapper.insert(x));
本地执行的时候是没有问题的

但是发布到线上测试环境之后,使用的是k8s容器部署的,执行插入之后,打印日志只有

日志没有影响行数,且数据库中没有插入任何数据,程序也没有报错。
后来尝试把迭代器替换成了
for(X x : list){ basemapper.insert(x) }
就没有问题了,这是为什么呢?

目前已知的区别是本地使用的是oracle jdk 1.8.0,线上测试使用的是openjdk version "1.8.0_232",暂时没有想到别的区别

一人暮らしda的主页 一人暮らしda | 初学一级 | 园豆:112
提问于:2023-06-16 16:13
< >
分享
最佳答案
0

可能是因为使用 foreach 迭代器批量插入数据时,MyBatis 没有正确地处理事务,导致数据没有被真正地插入到数据库中。而使用传统的 for 循环则可以正确地处理事务,因此数据可以被成功插入到数据库中。

MyBatis 在处理批量插入操作时,通常需要使用事务来保证数据的完整性和一致性。在使用 foreach 迭代器时,MyBatis 可能无法正确地处理事务,从而导致数据插入失败。为了避免这种情况,您可以尝试在插入操作之前手动开启事务,并在操作完成后手动提交事务。例如:

TransactionTemplate transactionTemplate = new TransactionTemplate(dataSource);  
transactionTemplate.execute(new TransactionCallback<Void>() {  
    public Void doInTransaction(TransactionStatus status) {  
        list.forEach(x -> basemapper.insert(x));  
        return null;  
    }  
});

上述代码中,我们使用了 Spring 的 TransactionTemplate 来手动处理事务。在 execute() 方法中,我们调用了 list.forEach() 方法来批量插入数据,并且在 doInTransaction() 方法中返回了 null 值。

通过这种方式,我们可以确保在批量插入数据时,MyBatis 可以正确地处理事务,从而避免数据插入失败的问题。

收获园豆:100
lanedm | 老鸟四级 |园豆:2396 | 2023-06-16 16:26

您好,我在日志中查看到的
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@41f3892a] was not registered for synchronization because synchronization is not active

JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2642cc4] will not be managed by Spring
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@41f3892a]
是否跟您说的这个问题相关呢。
为什么本地调试时能够插入成功呢。

一人暮らしda | 园豆:112 (初学一级) | 2023-06-16 16:37

@一人暮らしda: 1.本地调试连接的数据库,与web服务器连接的数据库,是否是同一个库;
2.数据库服务器的响应时间:如果数据库服务器的响应时间较快,例如在100毫秒以内,那么sqlconnection连接关闭时间可能会在几百毫秒之内。
3.网络延迟和带宽限制:如果网络延迟较严重或者带宽有限,或web服务器上搭了几十个站点,或web服务器性能较差,连接关闭时间可能会较长。例如,如果网络延迟达到100毫秒以上,连接关闭时间可能会在几秒到十几秒之间。
4.数据库操作的数据量和复杂度:如果一次SQL事务涉及大量的数据操作或者复杂的逻辑处理,那么连接关闭时间可能会较长。例如,如果一次SQL事务需要执行多张表的操作或者需要进行复杂的计算,连接关闭时间可能会在几秒到几十秒之间。
5.在上述情况下,在forEach中,假设第一个insert执行2秒关闭事务,而第二个insert在1.5秒的时候启动一个新的事务,那么就可能报错了,同一个表、同一个连接,前一个事务未完成,又启动新的事务
6.由于for循环是顺序排队执行的,不会有插入新事务的问题,所以没报错

lanedm | 园豆:2396 (老鸟四级) | 2023-06-16 16:51

@lanedm: 好的,感谢

一人暮らしda | 园豆:112 (初学一级) | 2023-06-16 17:05
其他回答(1)
0

for循环里写sql会严重影响性能,建议for循环处理数据,最后在循环外saveBatch()插入数据

《END》 | 园豆:202 (菜鸟二级) | 2023-08-17 13:45
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册