• 多线程事物造成死锁全面分析


    一 事物五大类

     二 事物使用区分

    1 自动回滚和手动回滚不能一起使用回报错冲突除非PROPAGATION_REQUIRES_NEW新事物才不会和自动事物冲突

    2 手动回滚包含两种

         1》 SqlSession

    • // 获取数据库连接,获取会话(内部自有事务)

    • SqlSession sqlSession = sqlContext.getSqlSession();

    • Connection connection = sqlSession.getConnection();

        2 》TransactionManager

     注意 DataSourceTransactionManager.rollback和 TransactionStatus.setRollbackOnly区别

    setRollbackOnlyrollback
    不同点控制范围小,资源释放需要配合自动事物控制范围大,释放不需要自动事物管理
    相同点能回滚能回滚

           三  下面是测试分析

    情况一手动事物死锁

     情况二手动事物不锁

     情况三自动+手动事物不锁表(注意手动需要开启新事物不然冲突)

    情况四自动+手动事物锁表

    情况五自动+手动事物锁表

    情况六自动+手动事物不锁表 

    1. 查看mysql事物锁
    2. //当前运行的所有事务 首先我们查看被锁表的进程
    3. SELECT * FROM information_schema.INNODB_TRX;
    4. //当前出现的锁
    5. SELECT * FROM information_schema.INNODB_LOCKs;
    6. //锁等待的对应关系
    7. SELECT * FROM information_schema.INNODB_LOCK_waits;
    8. 解决:kill事务,清理表数据,转移到历史表,检查定时任务
    9. 然后找到进程号,即 trx_mysql_thread_id
    10. 然后执行;
    11. kill 进程号;

    四 多线程事物推荐一下两种

    注意线程不能用太多,调整mysql最大连接数5.7默认151改成500,根据cpu情况来

    推荐最大核心数=cpu*2+1,但是还有其它线程使用sleep和await,所见建议处理大数据量的时候

    线程控制在10以内

    1. @Override
    2. public void testTranslationOfThreads6() throws SQLException {
    3. //准备数据50000条
    4. List list = new ArrayList<>();
    5. for (int i = 0; i < 50000; i++) {
    6. Cdr cdr = new Cdr();
    7. cdr.setSrc("" + i);
    8. cdr.setDatetime(DateUtils.formatTime(new Date()));
    9. list.add(cdr);
    10. }
    11. // 获取数据库连接,获取会话(内部自有事务)
    12. SqlSession sqlSession = sqlContext.getSqlSession();
    13. Connection connection = sqlSession.getConnection();
    14. try {
    15. // 设置手动提交
    16. connection.setAutoCommit(false);
    17. //获取mapper
    18. CdrMapper employeeMapper = sqlSession.getMapper(CdrMapper.class);
    19. //先做删除操作
    20. // employeeMapper.remove()
    21. //获取执行器
    22. ExecutorService service = ExecutorConfig.getThreadPool();
    23. List> callableList = new ArrayList<>();
    24. //拆分list
    25. List> lists = averageAssign(list, 5);
    26. AtomicBoolean atomicBoolean = new AtomicBoolean(true);
    27. for (int i = 0; i < lists.size(); i++) {
    28. if (i == lists.size() - 1) {
    29. atomicBoolean.set(false);
    30. }
    31. List list1 = lists.get(i);
    32. //使用返回结果的callable去执行,
    33. Callable callable = () -> {
    34. //让最后一个线程抛出异常
    35. if (!atomicBoolean.get()) {
    36. throw new JeecgBootException(001, "出现异常");
    37. }
    38. int insert = employeeMapper.insert(list1.get(0));
    39. return insert;
    40. };
    41. callableList.add(callable);
    42. }
    43. //执行子线程
    44. List> futures = service.invokeAll(callableList);
    45. for (Future future : futures) {
    46. //如果有一个执行不成功,则全部回滚
    47. if (future.get() <= 0) {
    48. connection.rollback();
    49. return;
    50. }
    51. }
    52. connection.commit();
    53. System.out.println("添加完毕");
    54. } catch (Exception e) {
    55. connection.rollback();
    56. log.info("error", e);
    57. throw new JeecgBootException(002, "出现异常");
    58. } finally {
    59. connection.close();
    60. }
    61. }

    1. @Override
    2. public void testTranslationOfThreads3() {
    3. long startTime = System.currentTimeMillis();
    4. //准备数据50000条
    5. List list = new ArrayList<>();
    6. for (int i = 0; i < 50000; i++) {
    7. Cdr cdr = new Cdr();
    8. cdr.setSrc("" + i);
    9. cdr.setDatetime(DateUtils.formatTime(new Date()));
    10. list.add(cdr);
    11. }
    12. // 线程数量
    13. final Integer threadCount = 2;
    14. //每个线程处理的数据量
    15. final Integer dataPartionLength = (list.size() + threadCount - 1) / threadCount;
    16. // 创建多线程处理任务
    17. ExecutorService studentThreadPool = Executors.newFixedThreadPool(threadCount);
    18. CountDownLatch threadLatchs = new CountDownLatch(threadCount);
    19. AtomicBoolean isError = new AtomicBoolean(false);
    20. try {
    21. for (int i = 0; i < threadCount; i++) {
    22. // 每个线程处理的数据
    23. List threadDatas = list.stream()
    24. .skip(i * dataPartionLength).limit(dataPartionLength).collect(Collectors.toList());
    25. studentThreadPool.execute(() -> {
    26. try {
    27. try {
    28. this.updateStudentsTransaction(transactionManager, transactionStatuses, threadDatas);
    29. } catch (Throwable e) {
    30. e.printStackTrace();
    31. isError.set(true);
    32. } finally {
    33. threadLatchs.countDown();
    34. }
    35. } catch (Exception e) {
    36. e.printStackTrace();
    37. isError.set(true);
    38. }
    39. });
    40. }
    41. // 倒计时锁设置超时时间 30s
    42. boolean await = threadLatchs.await(30, TimeUnit.SECONDS);
    43. // 判断是否超时
    44. if (!await) {
    45. isError.set(true);
    46. }
    47. } catch (Exception e) {
    48. e.printStackTrace();
    49. isError.set(true);
    50. }
    51. if (!transactionStatuses.isEmpty()) {
    52. if (isError.get()) {
    53. transactionStatuses.forEach(s -> transactionManager.rollback(s));
    54. } else {
    55. transactionStatuses.forEach(s -> transactionManager.commit(s));
    56. }
    57. }
    58. long endTime = System.currentTimeMillis();
    59. log.info("共耗时:{}", (endTime - startTime) / 1000 + "秒");
    60. System.out.println("主线程完成");
    61. }

  • 相关阅读:
    leetcode做题笔记203. 移除链表元素
    React报错之React Hook useEffect has a missing dependency
    开发了一个深度神经网络
    LeetCode 2895. 最小处理时间【贪心,排序】1351
    python环境移植,制作可以移植的python环境
    一文讲透彻Redis 持久化
    化工原理 --- 热量传递(补充)
    Android12之解封装NuMediaExtractor::setDataSource过程(四十七)
    HTML的特殊字符
    i.MX 6ULL 驱动开发 二十:RTC
  • 原文地址:https://blog.csdn.net/weixin_38501485/article/details/126403668