色空大师 2023-10-14 07:39 采纳率: 40.9%
浏览 8
已结题

循环查询数据后使用线程去更新数据有问题吗

#循环查询数据后使用线程去更新数据,如果更新速度慢,那么更新第一次数据时,线程中传入的可能是第3次或第4次查询出的数据吗
代码如下

package com.test.thread.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.test.thread.mapper.UserMapper;
import com.test.thread.pojo.User;
import com.test.thread.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author清梦
 * @site www.xiaomage.com
 * @company xxx公司
 * @create 2023-10-13 22:25
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    @Qualifier("taskExecutor")
    private TaskExecutor taskExecutor;

    @Override
    public void batchUpdate(){
        for (int i=0;i<20;i++){
            List<User> list = new ArrayList<>();
            Page<User> userPage = userMapper.selectPage(new Page<>(i, 500), null);
            List<User> users = userPage.getRecords();
            users.stream().forEach(user -> {
                user.setName("test1");
                list.add(user);
            });
            log.info("list:{}",list.toString());
            int finalI = i;
            taskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        //Thread.sleep(1000);
                    }catch (Exception e){
                        log.error("线程失败:{}",e);
                    }

                    long start = System.currentTimeMillis();
                    log.info("开始更新,下标:{},大小:{}", finalI,list.size());
                    updateBatchById(list);
                    log.info("更新结束,下标:{},大小:{},耗时:{}", finalI,list.size(),System.currentTimeMillis()-start);
                }
            });
        }
    }
}


实体类

@TableName("tb_user")
@Data
public class User {
    @TableId(type = IdType.AUTO)
    private int id;

    private String name;
}

线程池配置

@Configuration
public class MybatisConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}

问题:
1.实现类中的代码有漏洞吗?
问题原因:本人在对oracle数据库进行更新时,业务逻辑如上,但是发布生产环境没有更新数据,组长看了代码后说是这种写法有漏洞。线程执行慢,list每次循环会被重新生成。重新写了一个类后传入list,再去执行线程,这样就更新了。但是本地测试并没有问题没搞不懂为啥。
2.线程中使用Thread.sleep(3000);后,线程后面的步骤就不走了,线程中断了,这是为什么?
3.在线程中添加了循环,添加耗时,结果也没有循环10000次,更新操作也没有执行,这是为什么呢?

taskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (int j=0;j<10000;j++){
                            log.info("线程----第{}次查询",j);
                            userMapper.selectList(null);
                            log.info("线程----第{}次查询结束",j);
                        }
                        /*log.info("沉睡3秒");
                        long time = System.currentTimeMillis();
                        Thread.sleep(3000);
                        log.info("沉睡3秒结束,沉睡时间:{}",System.currentTimeMillis()-time);*/
                    }catch (Exception e){
                        log.error("线程失败:{}",e);
                    }

                    long start = System.currentTimeMillis();
                    log.info("开始更新,下标:{},大小:{}", finalI,list.size());
                    log.info("list:{}",list.toString());
                    updateBatchById(list);
                    log.info("更新结束,下标:{},大小:{},耗时:{}", finalI,list.size(),System.currentTimeMillis()-start);
                }
            });

4.代码循环时,到最后一次会出现线程中断异常,比如30万数据,更新到第60次后,走到线程中,进行更新时就会报错,提示线程中断。搞不懂为啥。

展开全部

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-10-14 16:19
    关注

    【以下回答由 GPT 生成】

    这段代码的执行流程如下:

    1. batchUpdate 方法开始执行,进入循环,循环次数为20次。
    2. 在每次循环中,首先创建一个空的 ArrayList 对象 list 用来存储要更新的用户数据。
    3. 调用 userMapperselectPage 方法查询用户数据并分页获取数据(每次500条)。
    4. 将查询结果中的每个用户的姓名设置为 "test1",并添加到 list 中。
    5. 打印输出 list 中的数据。
    6. 创建一个线程,在线程的 run 方法中编写更新逻辑(当前代码中没有具体更新逻辑)。
    7. 将线程提交给 taskExecutor 执行。
    8. 重复步骤2至7,直到循环结束。

    可能存在的问题: 在这段代码中,可能存在以下问题:

    1. 数据更新的逻辑没有具体实现,所以无法确定具体的更新情况。
    2. 在并发情况下,由于线程池的执行时间是不确定的,可能会导致更新逻辑中传入的用户数据是之前查询的数据,而不是最新的数据。
    3. 线程池的线程数量有限,如果循环次数较多,可能会导致某些线程无法得到合适的执行,从而影响数据更新的效率和结果。
    4. 没有对数据进行同步处理,可能会导致多个线程同时更新同一个用户的数据,从而引发数据不一致的问题。

    为了解决这些问题,可以进行以下改进:

    1. run 方法中编写具体的更新逻辑,确保每个线程都有正确的数据更新操作。
    2. 可以使用 synchronized 关键字或者 ReentrantLock 类来对更新逻辑进行同步处理,避免多个线程同时更新同一个用户的数据。
    3. 可以考虑使用 ThreadPoolExecutor 类,手动创建线程池对象,并设置合适的参数,以控制并发线程数量,避免线程过多或过少的情况。
    4. 可以在循环结束后,使用 CountDownLatch 或者 CyclicBarrier 类等来等待所有线程执行完毕,以确保所有数据都被正确更新。
    5. 最好进行性能测试和压力测试,评估在具体环境下的运行情况和表现,根据实际情况进行调整和优化。


    【相关推荐】



    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
编辑
预览

报告相同问题?

问题事件

  • 系统已结题 11月14日
  • 已采纳回答 11月7日
  • 修改了问题 10月14日
  • 创建了问题 10月14日

悬赏问题

  • ¥15 PADS Logic 原理图
  • ¥15 PADS Logic 图标
  • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
  • ¥20 气象站点数据求取中~
  • ¥15 如何获取APP内弹出的网址链接
  • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部