zoukankan      html  css  js  c++  java
  • 一次数据库死锁原因分析

    线上crm导出一份报表时长时没反应,日志一看:

     1 2017-09-25 13:45:58 [http-nio-8080-exec-60] ERROR: jdbc.sqltiming#exceptionOccured : 1469. PreparedStatement.executeBatch() FAILED! batching 3 statements: 1: update uwc_applyloan_attach set ATTACH_ID=112103 where ID=44602 2: 
     2 update uwc_applyloan_attach set ATTACH_ID=112106 where ID=44603 3: update uwc_applyloan_attach 
     3 set ATTACH_ID=112109 where ID=44604 
     4  {FAILED after 135899 msec}
     5 java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction
     6     at com.mysql.jdbc.SQLError.createBatchUpdateException(SQLError.java:1167)
     7     at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1778)
     8     at com.mysql.jdbc.PreparedStatement.executeBatchInternal(PreparedStatement.java:1262)
     9     at com.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:970)
    10     at net.sf.log4jdbc.StatementSpy.executeBatch(StatementSpy.java:526)
    11     at sun.reflect.GeneratedMethodAccessor387.invoke(Unknown Source)
    12     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    13     at java.lang.reflect.Method.invoke(Method.java:601)
    14     at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)
    15     at com.sun.proxy.$Proxy33.executeBatch(Unknown Source)
    16     at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    17     at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    18     at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
    19     at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185)
    20     at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    21     at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)
    22     at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1185)
    23     at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1261)
    24     at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
    25     at com.upg.ucars.framework.base.AbstractHibernateDAO$1.doInHibernate(AbstractHibernateDAO.java:172)
    26     at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
    27     at org.springframework.orm.hibernate3.HibernateTemplate.executeFind(HibernateTemplate.java:343)
    28     at com.upg.ucars.framework.base.AbstractHibernateDAO.queryByParam(AbstractHibernateDAO.java:147)
    29     at com.upg.ucars.framework.base.AbstractHibernateDAO.queryByParam(AbstractHibernateDAO.java:92)
    30     at com.upg.tenant.yuntao.core.UwcApplyloanAttachDaoImpl.getByApplyId(UwcApplyloanAttachDaoImpl.java:19)
    31     at com.upg.es.seal.core.EsSealServiceImpl.generateDownloadData(EsSealServiceImpl.java:568)
    32     at com.upg.es.seal.core.EsSealServiceImpl$$FastClassByCGLIB$$f4dc2f5b.invoke(<generated>)
    33     at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    34     at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
    35     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    36     at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)
    37     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    38     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    39     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    40     at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)
    41     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    42     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    43     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    44     at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)
    45     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    46     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    47     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    48     at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
    49     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    50     at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
    51     at com.upg.es.seal.core.EsSealServiceImpl$$EnhancerByCGLIB$$1d4e14b1.generateDownloadData(<generated>)
    UwcApplyloanAttachDaoImpl.getByApplyId(UwcApplyloanAttachDaoImpl.java:19)这句造成了锁超时,但奇怪的是这个是个查询语句。
    分析了下Hibernate源码,原来在查询中还需要先Flush一下,看org.hibernate.impl.SessionImpl源码:

    public
    List list(String query, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); queryParameters.validateParameters(); HQLQueryPlan plan = getHQLQueryPlan( query, false ); autoFlushIfRequired( plan.getQuerySpaces() ); List results = CollectionHelper.EMPTY_LIST; boolean success = false; dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called try { results = plan.performList( queryParameters, this ); success = true; } finally { dontFlushFromFind--; afterOperation(success); } return results; }



        /**
         * detect in-memory changes, determine if the changes are to tables
         * named in the query and, if so, complete execution the flush
         */
        protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
            errorIfClosed();
            if ( ! isTransactionInProgress() ) {
                // do not auto-flush while outside a transaction
                return false;
            }
            AutoFlushEvent event = new AutoFlushEvent(querySpaces, this);
            AutoFlushEventListener[] autoFlushEventListener = listeners.getAutoFlushEventListeners();
            for ( int i = 0; i < autoFlushEventListener.length; i++ ) {
                autoFlushEventListener[i].onAutoFlush(event);
            }
            return event.isFlushRequired();
        }

    org.hibernate.event.def.AbstractFlushingEventListener

        protected void performExecutions(EventSource session) throws HibernateException {
    
            log.trace("executing flush");
    
            try {
                session.getJDBCContext().getConnectionManager().flushBeginning();
                // we need to lock the collection caches before
                // executing entity inserts/updates in order to
                // account for bidi associations
                session.getActionQueue().prepareActions();
                session.getActionQueue().executeActions();
            }
            finally {
                session.getJDBCContext().getConnectionManager().flushEnding();
            }
        }

    org.hibernate.jdbc.AbstractBatcher

        public void executeBatch() throws HibernateException {
            if (batchUpdate!=null) {
                try {
                    try {
                        doExecuteBatch(batchUpdate);
                    }
                    finally {
                        closeStatement(batchUpdate);
                    }
                }
                catch (SQLException sqle) {
                    throw JDBCExceptionHelper.convert(
                            factory.getSQLExceptionConverter(),
                            sqle,
                            "Could not execute JDBC batch update",
                            batchUpdateSQL
                        );
                }
                finally {
                    batchUpdate=null;
                    batchUpdateSQL=null;
                }
            }
        }

    看到这里就明白了, doExecuteBatch(batchUpdate); 如果有待Flush的update操作存在,前面一次操作的长事务还没结束而同时另外一个长事务操作又开始了,到了getByApplyId这里又去更新同样的记录就得等待锁释放了

     

     

     

    喜欢艺术的码农
  • 相关阅读:
    IntelliJ Idea 2017 免费激活方法
    RabbitMq、ActiveMq、ZeroMq、kafka之间的比较
    Oracle锁的机制
    序列化和持久化的区别
    Hibernate框架之get和load方法的区别
    Hibernate框架之入门案例
    Oracle添加数据报文字与格式字符串不匹配错误
    Linux设备驱动程序 之 异步通知
    Linux设备驱动程序 之 poll和select
    Linux设备驱动程序 之 休眠
  • 原文地址:https://www.cnblogs.com/zjhgx/p/7773202.html
Copyright © 2011-2022 走看看