java - 超过锁定等待超时;尝试用 spring 和 Mysql 重启事务 Java

标签 java mysql multithreading spring database-deadlocks

在我的应用程序中,我使用带有普通 jdbc 的 spring。 并且有多个线程执行各种数据库操作。例如检查表中是否不存在值然后将其插入。问题是我遇到了异常>> 超出锁定等待超时;尝试重新启动事务 我已经检查了 mysql SHOW ENGINE INNODB STATUS\G;它给出了 desc

------------
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 使用行级锁并且删除它需要索引锁(独占)和间隙锁作为共享。由于某种原因,它不会发布它。然后对于同一个表中的其他一些插入,它需要那个锁.. 我得到了这个异常(exception)。谁能建议我如何解决这个问题? 其他需要的详细信息>>

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" />

这就是我在 spring 事务中使用普通 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;

} 

最佳答案

您的问题出在您的数据库操作上,与您访问数据库所使用的技术无关。

出现数据库死锁的唯一原因是在某些事务/操作中,您以相反的顺序锁定资源。

例如:

交易 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,row 1 的锁定。同时,第二个事务获得了对 table2,第 2 行 的锁定。

然后,第一个事务想要从 table2 中获取第 2 行,但是不能,因为第二个事务已经有了它。因此,tr1 必须等待。

同样,tr2 也必须等待,因为它想从表 1 中获取 第 1 行,但 tr1 持有它。所以,他们在等待对方,只有超时才能释放(并回滚)其中一个事务(另一个可以运行,如果它有足够的剩余时间)。

解决方案:

您为您的表赋予优先级,并始终按该顺序使用它们(例如 table1table2 )。 如果您的逻辑要求您首先需要 table2 中的一些数据,您可以考虑颠倒顺序或锁定 table1 中肯定会覆盖最终操作中涉及的行的最小可能行集(可能是您必须锁定 table1 中的所有行,或者改为放置表级锁)。

是的,所有操作,包括 GUI 查询、后台进程、报告等,都必须使用相同的顺序。

关于java - 超过锁定等待超时;尝试用 spring 和 Mysql 重启事务 Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24379132/

相关文章:

Java,使用比较器对ArrayList进行排序

java - 使用数据源未选择数据库 SQLException

java - JxBrowser导致线程死锁120秒

java - 使用 Apache Camel 和 Spring,我可以使用属性构建 uri 吗?

php - 使用 php mysqli 将时间戳提交到 mysql 数据库

mysql - MYSQL中如何选择两列之间的时间?

站点管理员配置的 PHP 任务计划程序

c# - 处理数千个 UDP 数据包并使用 Threads 将它们保存在远程数据库中的最佳方法是什么?

c++ - std::thread 错误(线程不是 std 的成员)

c# - 保存位图并使用 graphics.copyFromScreen parallel-y 时出现 InvalidOperationException