簡體   English   中英

超過了鎖定等待超時; 嘗試使用spring和Mysql重新啟動事務Java

[英]Lock wait timeout exceeded; try restarting transaction Java with spring and Mysql

在我的應用程序中,我使用帶有純jdbc的spring。 並且有多個線程執行各種數據庫操作。例如檢查表中是否不存在值,然后將其插入。 問題是我正在獲取異常>> 超出了鎖定等待超時; 嘗試重新啟動事務,我已經在mysql SHOW ENGINE INNODB STATUS \\ G中簽入; 它給出了描述

------------
TRANSACTIONS
------------
Trx id counter D467
Purge done for trx's n:o < D459 undo n:o < 0
History list length 1050
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 64, OS thread handle 0xa6a0ab40, query id 9370 localhost root
SHOW ENGINE INNODB STATUS
---TRANSACTION D466, ACTIVE 22 sec
5 lock struct(s), heap size 320, 2 row lock(s), undo log entries 2
MySQL thread id 74, OS thread handle 0xa6c9eb40, query id 9369 localhost 127.0.0.1 root
Trx read view will not see trx with id >= D467, sees < D457
---TRANSACTION D464, ACTIVE 24 sec
5 lock struct(s), heap size 320, 2 row lock(s), undo log entries 2
MySQL thread id 70, OS thread handle 0xa6aceb40, query id 9354 localhost 127.0.0.1 root
Trx read view will not see trx with id >= D465, sees < D457
---TRANSACTION D462, ACTIVE 28 sec
2 lock struct(s), heap size 320, 1 row lock(s)
MySQL thread id 73, OS thread handle 0xa6c3cb40, query id 9347 localhost 127.0.0.1 root
Trx read view will not see trx with id >= D463, sees < D457
---TRANSACTION D45A, ACTIVE 87 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 34 lock struct(s), heap size 2496, 81 row lock(s), undo log entries 151
MySQL thread id 72, OS thread handle 0xa6a3bb40, query id 9054 localhost 127.0.0.1 root update
Insert into TABLE_1 ( ID,NAME,STATUS)values (44545,'temp','disable')
Trx read view will not see trx with id >= D45B, sees < D450
------- TRX HAS BEEN WAITING 26 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 159967 n bits 312 index `PRIMARY` of table `test2`.`TABLE_1` trx id D45A lock mode S locks rec but not gap waiting
Record lock, heap no 67 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 4; hex 80016687; asc   f ;;
 1: len 6; hex 00000000d457; asc      W;;
 2: len 7; hex 2f0001dda310ee; asc /      ;;
 3: len 10; hex 4d6f68642e20417a697a; asc Mohd. Aziz;;
 4: SQL NULL;
 5: SQL NULL;
 6: len 1; hex 4d; asc M;;
 7: SQL NULL;
 8: len 1; hex 30; asc 0;;
 9: len 10; hex 496e646976696475616c; asc Individual;;
 10: len 6; hex 414354495645; asc ACTIVE;;
 11: len 4; hex 53a90e01; asc S   ;;

------------------
---TRANSACTION D457, ACTIVE 130 sec
77 lock struct(s), heap size 5504, 141 row lock(s), undo log entries 287
MySQL thread id 71, OS thread handle 0xa6affb40, query id 9001 localhost 127.0.0.1 root
Trx read view will not see trx with id >= D458, sees < D42E
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
2386 OS file reads, 1108 OS file writes, 155 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 884, seg size 886, 12 merges
merged operations:
 insert 102, delete mark 6, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 553253, node heap has 18 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---
LOG

我只是從我的研究中了解到,mysql INNODB使用行級鎖,要刪除它,需要共享索引鎖(排他)和間隙鎖。 由於某種原因,它不會釋放它。 然后在同一張桌子上的其他插入它需要那個鎖..我得到了這個排他。 誰能建議我如何解決此問題? 其他必需的詳細信息>>

datasource.xml

<bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
      <property name="url" value="jdbc:mysql://localhost:3306/test2" />
      <property name="driverClassName" value="com.mysql.jdbc.Driver" />
      <property name="username" value="root" />
      <property name="password" value="root" />
      <property name="removeAbandoned" value="true" />
      <property name="initialSize" value="20" />
      <property name="maxActive" value="30" />
    </bean>

    <!-- Enable Annotation based Declarative Transaction Management -->
    <tx:annotation-driven proxy-target-class="true"
        transaction-manager="transactionManager" />

這就是我在春季交易中使用普通jdbc的方法>>

@Repository
@Transactional(rollbackFor=Exception.class)
public class StudentDaoImpl implements StudentDao {

private static final Logger log = Logger
        .getLogger(StudentDaoImpl.class);

@Autowired
private DataSource dataSource;

PreparedStatement stmt = null;
        ResultSet rs = null;
        int count = 0;
        String sql = "Select count(*) from SOMETABLE where ID= ?";
        Connection conn = null;
        try {
            conn = DataSourceUtils.getConnection(dataSource);
            stmt = conn.prepareStatement(sql);
            stmt.setInt(1, id);
            rs = stmt.executeQuery();

            while (rs.next()) {
                count = rs.getInt(1);
            }

        } catch (SQLException e) {
            e.printStackTrace();
            log.error(e);
            throw new Exception(e);
        } finally {
            close(stmt, rs);
            DataSourceUtils.releaseConnection(conn, dataSource);
        }
        return count;

} 

即使您提到學習曲線,我也建議使用JdbcTemplate。 沒有太多的東西要學習,也不難。 JdbcTemplate取消了所有樣板JDBC代碼:

@Repository
@Transactional(rollbackFor=Exception.class)
public class StudentDaoImpl implements StudentDao {

    private static final Logger log = Logger
        .getLogger(StudentDaoImpl.class);

    private final JdbcTemplate jdbcTemplate;

    private static final String COUNT_SOMETHING = "SELECT COUNT(*) "
        + "FROM SOMETABLE WHERE ID=?";

    @Autowired
    public StudentDaoImpl(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public int countSomething() {
        return jdbcTemplate.queryForObject(COUNT_SOMETHING, Integer.class, 1);
    }
} 

您的問題出在數據庫操作上,與您用來訪問數據庫的技術無關。

出現數據庫死鎖的唯一原因是,在某些事務/操作中,您以相反的順序鎖定資源。

例如:

交易1:

UPDATE table1 SET col=val WHERE id=1
DELETE FROM table2 WHERE id=2

交易2:

UPDATE table2 SET col=val WHERE id=2
UPDATE table1 SET col=val WHERE id=1

第一個事務獲取對table1第1行的鎖定。 同時,第二個事務鎖定到table2第2行

然后,第一個事務想要從table2中獲取行2 ,但是不能,因為第二個事務已經擁有它。 因此,tr1必須等待。

同樣,tr2也必須等待,因為它想從table1中獲取行1 ,但是tr1保留了它。 因此,他們彼此等待,只有超時可以釋放(並回滾)其中一個事務(如果剩余時間足夠,則另一個可以運行)。

解決方案:

您將優先級賦予表,並始終按該順序使用它們(例如table1table2 )。 如果您的邏輯指示您首先需要從table2中獲取一些數據,則可以考慮顛倒順序,或者將鎖鎖定在table1中最小的可能行集合中,這肯定會覆蓋最終操作中涉及的行(可能是您必須鎖定table1中的所有行,或者放置表級鎖定)。

是的,所有操作(包括GUI查詢,后台進程,報告等)都必須使用相同的順序。

暫無
暫無

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

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