• Session问题以及解决方案


    Mysql事务锁等待超时 Lock wait timeout exceeded; try restarting transaction

    问题场景
    问题出现环境:
    1、在同一事务内先后对同一条数据进行插入和更新操作;
    2、多台服务器操作同一数据库;
    3、瞬时出现高并发现象;

    原因分析
    在高并发的情况下,Spring事物造成数据库死锁,后续操作超时抛出异常。
    Mysql数据库采用InnoDB模式,默认参数:innodb_lock_wait_timeout设置锁等待的时间是50s,一旦数据库锁超过这个时间就会报错。

    临时解决方案
    我们可以通过到information_schema 中来进行查找被锁的语句。

    我们可以用下面三张表来查原因:
    innodb_trx 当前运行的所有事务
    innodb_locks 当前出现的锁
    innodb_lock_waits 锁等待的对应关系
    如果数据库中有锁的话,我们可以使用这条语句来查看:
    select * from information_schema.innodb_trx
    LOCK WAIT为占用系统资源的语句,我们需要杀掉这个锁,执行 kill 线程id号

    终极解决方案
    1.细化Session操作的时间
    将验证逻辑,获取数据逻辑等内容单独拉出,数据准备好之后,打开session后进行数据库操作,然后提交session。
    2.数据一致性要求比较低的话,可以设置session自动提交。
    sqlSessionFactory.openSession(true)
    3.及时关闭session,也可以采用以下方法新建session
    try(SqlSession sqlSession = sqlSessionFactory.openSession()) { // run sth. }
    4.增加锁等待时间,即增大下面配置项参数值,单位为秒(s)
    innodb_lock_wait_timeout=500

    Error querying database. Cause: java.lang.ClassCastException: org.apache.ibatis.executor.ExecutionPlaceholder cannot be cast to java.util.List

    问题场景&原因分析
    以 SqlSession sqlSession = sqlSessionFactory.openSession() 方式创建的sqlSession 在多线程下并发查询数据时报错
    终极解决方案
    1.继续使用sqlSession ,但是不同线程,使用不同的session,不公用一个session
    2.不使用sqlSession,包装成SqlSessionTemplate,使用spring提供的代理。

    Druid异常:wait millis 40000, active 600, maxActive 600

    问题场景
    session连接数创建过多,没有及时关闭
    原因分析
    1.session没有主动关闭
    2.session打开后代码报错,无法关闭session
    终极解决方案
    在 try catch finally 语句块内,在finally 内关闭session

    全面解决问题代码示例

    综合上面各种问题,采取如下方式:
    1.使用ThreadLocal存储session,线程的所有session都从ThreadLocal获取
    2.finally内 进行 session的提交,session的关闭,ThreadLocal的删除
    3.最大线程数 小于等于 最大连接数
    整体处理方法如下:

    // 最大线程数为200,此数据对应数据库配置的 maxActive ,最大线程数要<=maxActive 
    private ExecutorService threadPool = new ThreadPoolExecutor(0, 200, 60,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(10),
                new ThreadFactoryBuilder().setNameFormat("thread-" + this.getClass().getSimpleName() + "-kafka-metrics-%d").setDaemon(true).build(),
                new ThreadPoolExecutor.DiscardOldestPolicy());;
    private static final ThreadLocal<SqlSession> threadSessionLocal = new ThreadLocal<>();
    for(){
      threadPool.submit(() -> {
         this.handleSourceData(params);
      });
    }
    
    
      public void handleSourceData(Object params){
        if(threadSessionLocal.get() == null){
            SqlSession sqlSession = sessionFactory.openSession();
            threadSessionLocal.set(sqlSession);
        }
        try{
        SqlSession sqlSession = threadSessionLocal.get();
        //sqlSession 进行后续操作
        }catch (Exception e){
        }finally{
              threadSessionLocal.get().commit();
              threadSessionLocal.get().close();
              threadSessionLocal.remove();
        }
      }
  • 相关阅读:
    Idea如果添加Maven模块
    idea在debugger模式下无法启动,但是在run模式下可以启动的问题
    Idea搭建SpringMVC框架(初次接触)
    Intellij IDEA 环境 tomcat 启动设置
    Winform .NET 利用NPOI导出大数据量的Excel
    unity3D AudioMixer+Slider实现音量调节,多音效控制(主音量,背景音,特效音等)
    unity3D 点击按钮暂停和继续游戏
    unity3D AsyncOperation异步加载场景&百分比效果
    unity3D 实现2D游戏背景层交错感(视觉差)
    unity3D 重新加载当前场景&加载当前场景的下一个场景
  • 原文地址:https://www.cnblogs.com/cuiyf/p/13271811.html
Copyright © 2020-2023  润新知