houys 发表于 2024-1-15 11:23:45

事务死锁怎么处理

情况:服务端内查询订单表行数(id=参数),不存在则新增,存在则删除后再新增

可能会出现的问题:在这个服务端执行的过程中,另外的用户上传了相同的数据。
因为第一次的事务还没有关闭,即使第一次进行了新增数据,但是第二次查询行数还是为零
第二次就也会执行新增操作。就出现了重复行。
有可能也会出现死锁

Grayson.Shang 发表于 2024-1-15 11:23:46

大佬您好,我看咱们群里发的图片,数据库使用的是SQL Server,在调用事务命令的时候,咱们的事务设置的隔离级别是不是“串行化(Serializable)”
通过完全串行化的方式执行事务,确保一个事务执行的效果等同于它们是顺序执行的。

解决了幻读的问题。

这种隔离级别可能带来较大的性能开销,并且增加了死锁的可能性。
所以使用了串行化,本身就是为了数据的一致性,会增加死锁的可能

咱们试试看,在事务命令的外部是否可以捕获到死锁的异常,因为看报错信息,若是死锁了之后,会将事务关闭掉,所以只需要在死锁了之后,重新执行一下命令,咱们使用异常捕获命令捕获一下死锁的异常,捕获到之后,重新调用一下命令,看看是否可行

JC壹玖玖伍 发表于 2024-1-15 16:12:18

Grayson.Shang 发表于 2024-1-15 15:59
大佬您好,我看咱们群里发的图片,数据库使用的是SQL Server,在调用事务命令的时候,咱们的事务设置的隔离 ...

“咱们试试看,在事务命令的外部是否可以捕获到死锁的异常,因为看报错信息,若是死锁了之后,会将事务关闭掉,所以只需要在死锁了之后,重新执行一下命令,咱们使用异常捕获命令捕获一下死锁的异常,捕获到之后,重新调用一下命令,看看是否可行”

使用try catch?

Grayson.Shang 发表于 2024-1-15 16:27:36

是的,服务端命令中的try-catch,就是异常捕获命令

houys 发表于 2024-1-16 11:25:40

Grayson.Shang 发表于 2024-1-15 15:59
大佬您好,我看咱们群里发的图片,数据库使用的是SQL Server,在调用事务命令的时候,咱们的事务设置的隔离 ...

最主要的问题是,如果没有死锁就会出现重复行,在一个事务未提交之前另一个事务进行查询新增操作。
就出现了重复行

houys 发表于 2024-1-16 11:26:11

JC壹玖玖伍 发表于 2024-1-15 16:12
“咱们试试看,在事务命令的外部是否可以捕获到死锁的异常,因为看报错信息,若是死锁了之后,会将事务关 ...

捕可以捕获到,但是主要是出现重复行的问题

Grayson.Shang 发表于 2024-1-16 14:13:55

大佬您好,能具体的说一下咱们的业务场景吗,可能串行化隔离级别的事务操作,操作细节和咱们想要的有些区别,所以想了解一下咱们具体的场景。

我现在大概可以理解您说的需求,咱们是希望每次执行事务之前对数据表增加“表级锁”的“排它锁”,这样在事务执行期间,其他的事务不能对数据表进行查询,更不能对数据表做其他修改数据的操作,等上一个事务执行完成了,再开始执行下一个事务,您看我对您的需求描述的有问题没。

houys 发表于 2024-1-16 14:47:55

Grayson.Shang 发表于 2024-1-16 14:13
大佬您好,能具体的说一下咱们的业务场景吗,可能串行化隔离级别的事务操作,操作细节和咱们想要的有些区别 ...

情景就是   传递数据到服务端命令接收,判断这行数据是否存在于表中,存在则修改,不存在则新增
出现的问题是包含这个事务的服务端有时候会很慢,不清楚慢的原因
就导致了 短时间内连续触发就会查到的都是不存在于表中,结果都进行了添加操作。数据就错误了
你描述的事务锁级别是符合的,但是我不清楚会不会对其他的需要使用到这张表的业务产生什么影响
比如其他事务一直排队导致操作很慢之类的

Grayson.Shang 发表于 2024-1-16 17:37:03

已和楼主联系,将事务的隔离级别设置成,“序列化”之后,重复添加数据的情况暂时没有再出现,死锁可能会偶尔出现


出现死锁之后,通过异常捕获命令,捕获异常,捕获到之后,重新再调用一下服务端命令就可以了

中文 发表于 2024-7-15 17:25:55

出现死锁可以用存储过程这个给KILL掉BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE thread_id BIGINT;
    DECLARE cur1 CURSOR FOR
      SELECT ID
      FROM information_schema.processlist
      WHERE TIME > 120 AND COMMAND != 'Sleep' AND USER != 'system user';
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur1;

    read_loop: LOOP
      FETCH cur1 INTO thread_id;
      IF done THEN
            LEAVE read_loop;
      END IF;

      SET @s = CONCAT('KILL ', thread_id);
      PREPARE stmt FROM @s;
      EXECUTE stmt;
      DEALLOCATE PREPARE stmt;
    END LOOP;

    CLOSE cur1;
END
可以把这个存储过程放异常捕获
页: [1] 2
查看完整版本: 事务死锁怎么处理