簡體   English   中英

使用多個線程更新數據庫時如何避免“鎖定超時”?

[英]how to avoid “lock timeout” when updating DB using multiple threads?

我正在嘗試使用多個線程更新表。 但我不是同時更新相同的記錄/行。 我正在將表分組到不同的組中並嘗試同時更新它們。 但是,我一直在收到鎖定的超時錯誤。

我正在使用Hibernate,Spring MVC,ThreadPoolTask​​Executor和MySQL。 我從另一個數據庫架構獲取數據並更新我自己的數據庫。 數據是巨大的,這就是為什么我想使用多線程,所以它可以更快地完成。 但是,它會產生“鎖定超時”錯誤。 有人可以幫忙嗎? 謝謝你的好心。

我調用sessionFactory.getCurrenSession()來更新數據庫表。

這是我的配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}">
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="taskExecutor"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="5" />
        <property name="maxPoolSize" value="10" />
        <property name="WaitForTasksToCompleteOnShutdown" value="true" />
    </bean>

這是我的堆棧跟蹤:

WARN : org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1205, SQLState: 41000
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Lock wait timeout exceeded; try restarting transaction
Exception in thread "taskExecutor-5" Exception in thread "taskExecutor-4" Exception in thread "taskExecutor-2" org.hibernate.exception.LockTimeoutException: could not execute statement
    at org.hibernate.dialect.MySQLDialect$1.convert(MySQLDialect.java:407)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:136)
    at org.hibernate.hql.internal.ast.exec.BasicExecutor.execute(BasicExecutor.java:103)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.executeUpdate(QueryTranslatorImpl.java:413)
    at org.hibernate.engine.query.spi.HQLQueryPlan.performExecuteUpdate(HQLQueryPlan.java:282)
    at org.hibernate.internal.SessionImpl.executeUpdate(SessionImpl.java:1289)
    at org.hibernate.internal.QueryImpl.executeUpdate(QueryImpl.java:116)
   org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1084)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4232)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4164)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2838)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2082)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2334)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2262)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2246)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
    ... 25 more

“鎖定等待超時”總是會發生(即使在一次事務中有大量插入),也沒有解決它的靈丹妙葯。 但是當我試圖在一個(相對較小的)表中更新所有記錄的一半而另一半被另一個服務器修改時,我設法繞過它。

  • 查看事務中的所有SQL語句。
    使用explain來確保盡可能使用索引。 刪除作為事務一部分不需要的任何語句。
  • 優化事務中SQL語句的順序。
    這對我來說是一個試驗和錯誤,但試着想象來自多個線程/連接的SQL語句的哪個順序可能更容易處理數據庫。 在我的情況下,只需切換兩個SQL語句的順序使“鎖定等待超時”發生的頻率降低。
  • 更新較小的子集。
    這最終解決了我的“鎖定等待超時”。 在我的例子中,有一個索引列允許我將較大的更新集划分為較小的子集。 所以現在一個大的更新事務變成了大約十個更小的更新事務。 請記住,您需要能夠在崩潰后繼續執行較小的事務(即數據必須保持一致,以便您的應用程序可以重做操作並獲得相同的結果)。

多線程是否會提高吞吐量(每秒更新的行數)還有待觀察:它取決於更新集的大小(網絡延遲)以及MySQL如何有效地處理表的鎖以更新行。 使用兩個線程/連接而不是一個時,您可能只會看到一個微小的改進。

[編輯]還要注意數據庫觸發器/程序:它們會以不良方式影響性能。

也許你可以嘗試降低隔離級別 如果有幫助你可以挖掘更多。 它應該加快多線程環境中的執行速度。

如果您正在使用注釋,則可以通過事務類之上的@Transactional(isolation=Isolation.READ_UNCOMMITTED)實現此目的。

這似乎是數據庫端的超時。 我猜數據庫是限制因素,因此在應用程序中添加線程無濟於事。

如果你想使用線程加速,我建議只使用兩個線程。 當一個線程從另一個數據庫讀取時,第二個線程寫入MySQL數據庫。

請注意,如果兩個數據庫都在同一個數據庫服務器上,那么即使這樣也無濟於事。 您需要更快的數據庫或更強大的數據庫機器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM