• postgresql 并发update下导致的死锁问题


    一、死锁问题背景

    在收据批量打印时,由于采用异步并发触发打印,同时触发打印(九千多数据 每隔50ms触发一次),导致了并发执行引起在接口更新打印次数时postgresql发生死锁问题,

    具体报错如下:

     1 ### The error occurred while setting parameters
     2 ### SQL: update t_sc_receipt set print_num = coalesce(print_num,0) + 1                       ,print_ts=?
     3 ### Cause: org.postgresql.util.PSQLException: ERROR: deadlock detected
     4   详细:Process 19540 waits for ShareLock on transaction 12520113; blocked by process 19539.
     5 Process 19539 waits for ShareLock on transaction 12520112; blocked by process 19540.
     6   建议:See server log for query details.
     7   在位置:while rechecking updated tuple (329,3) in relation "t_sc_receipt"
     8 ; SQL []; ERROR: deadlock detected
     9   详细:Process 19540 waits for ShareLock on transaction 12520113; blocked by process 19539.
    10 Process 19539 waits for ShareLock on transaction 12520112; blocked by process 19540.
    11   建议:See server log for query details.
    12   在位置:while rechecking updated tuple (329,3) in relation "t_sc_receipt"; nested exception is org.postgresql.util.PSQLException: ERROR: deadlock detected
    13   详细:Process 19540 waits for ShareLock on transaction 12520113; blocked by process 19539.
    14 Process 19539 waits for ShareLock on transaction 12520112; blocked by process 19540.
    15   建议:See server log for query details.
    16   在位置:while rechecking updated tuple (329,3) in relation "t_sc_receipt"
    17     at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:263)
    18     at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
    19     at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
    20     at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:368)
    21     at com.sun.proxy.$Proxy57.update(Unknown Source)
    22     at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:254)
    23     at com.xxx.framework.mybatis.dao.impl.MyBatisDaoImpl.updateBySql(MyBatisDaoImpl.java:531)
    24     at com.xxx.dscsettle.receipt.ReceiptService.updatePrintNum(ReceiptService.java:160)
    25     at com.xxx.dscsettle.receipt.ReceiptService$$FastClassBySpringCGLIB$$82e91731.invoke(<generated>)
    26     at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    27     at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:651)
    28     at com.xxx.dscsettle.receipt.ReceiptService$$EnhancerBySpringCGLIB$$67b6a353.updatePrintNum(<generated>)
    29     at com.alibaba.dubbo.common.bytecode.Wrapper72.invokeMethod(Wrapper72.java)
    30     at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:46)
    31     at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:72)
    32     at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53)
    33     at com.onlyou.framework.log.DubboLogServiceFilter.invoke(DubboLogServiceFilter.java:28)
    34     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    35     at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:64)
    36     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    37     at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42)
    38     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    39     at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
    40     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    41     at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
    42     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    43     at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:61)
    44     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    45     at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:132)
    46     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    47     at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
    48     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    49     at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38)
    50     at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    51     at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:98)
    52     at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:98)
    53     at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170)
    54     at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52)
    55     at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:81)
    56     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    57     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    58     at java.lang.Thread.run(Thread.java:745)
    59 Caused by: org.postgresql.util.PSQLException: ERROR: deadlock detected
    60   详细:Process 19540 waits for ShareLock on transaction 12520113; blocked by process 19539.
    61 Process 19539 waits for ShareLock on transaction 12520112; blocked by process 19540.
    62   建议:See server log for query details.

    二、原因分析

    从报错的提示我们知道了在数据库postgresql发生了死锁(ERROR: deadlock detected  侦测到了死锁发生),而且可以定位是在并发更新打印次数的时候发生的,正常的逻辑下,分页去不断更新收据的打印次数应该是不会出错的,在这边批量更新打印次数时出现了错误。

    1.死锁是由于资源的相互竞争引起的,在update数据的时候应该是数据库行锁导致的

    2.因为批量修改是一个默认的事务,所以如果没有全部修改完,索引是不会被放开的,所以才会在并发的多次访问中出现死锁,

    3.研究出现问题的原因,发现最可能得是重复的行锁导致的,最终才查出原因是因为代码逻辑的原因,未传更新idList,而sql当中又进行了空的判断,导致每次都去更新全部的表数据,由于不同事务直接的相互等待,得不到资源,导致了死锁。

    三、问题解决与拓展

    批量更新的死锁解决方案有以下两种

    1.将批量update通过for循环改成单条修改,但是这个方法对服务器的压力增大

    2.在更新数据的时候进行一次筛选,将重复的数据剔除出去

    在本次问题解决当中,只需将代码中传入正确的idLIst即可解决问题,因为本身进行迭代是没有进行重复upadate的。

    疑问:并发update下postgresql就会出现shareLock死锁吗?

    一般情况下的多次update应该不会导致死锁,而在事务当中的update则比较可能发生死锁现象。

    同时,也看到了一位博主说postgresql 并发update的死锁问题可能是一些版本出现的bug,以及可能可以进行解决的设置以下两个参数进行解决:

    autovacuum_vacuum_scale_factor = 0.03
    autovacuum_analyze_scale_factor = 0.03


    参考地址:http://blog.chinaunix.net/uid-20726500-id-4773950.html
    https://blog.51cto.com/372550/2387517

  • 相关阅读:
    python操作adb代码
    android sdcard 权限管理策略研究
    glom模块的使用(二)
    爬虫错误汇总
    微博展开全文获取
    数据清洗之微博内容清洗
    Esxi5-管理平台vcenter5.0_数据库迁移流程
    migrating-vcenter-database-express-to-sql-2008-r2
    Centos生成SSL证书的步骤
    找到一篇关于2.4/5G信道的新介绍
  • 原文地址:https://www.cnblogs.com/zluckiy/p/12173497.html
Copyright © 2020-2023  润新知