MariaDB。使用事务回滚而不锁定表

时间:2019-06-01 19:54:20

标签: mysql mysqli transactions mariadb rollback

在网站上,当用户发表评论时,我会进行几个查询,即插入和更新。 (在MariaDB 10.1.29上)

我使用BEGIN TRANSACTION,因此,如果任何查询在任何给定时间失败,我都可以轻松地回滚并删除所有更改。 现在,我注意到这锁定了某些表或行,并且在查询运行时我没有说话,这很明显,但是直到事务未关闭。

好处是它不会阻止UPDATE,并且DELETE仅在它们共享一个公用索引键(同一页的注释)时才被锁定。 但是随后,INSERT锁定了任何INSERT中的表。

我可以执行任何不会从新插入中锁定表的事务(在事务正在进行时,而不是实际查询),或任何其他方法可以让我方便地“撤消”在某点之后完成的任何查询吗?

PD:

 [Table] => comment  
 [Create Table] => CREATE TABLE `comment` (  
`com_id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
`com_p_id` int(10) unsigned NOT NULL,  
`com_cont` varchar(282) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,  
`com_user` varchar(22) COLLATE utf8_bin NOT NULL,  
`com_us_id` int(10) unsigned NOT NULL,  
`reply_id` int(10) unsigned DEFAULT NULL,  
`replies` mediumint(8) unsigned NOT NULL DEFAULT '0',  
`noti_reply` int(10) unsigned DEFAULT NULL,  
PRIMARY KEY (`com_id`) USING BTREE,  
KEY `coments_ibfk_1` (`com_p_id`),  
KEY `reply_id` (`reply_id`)  
) ENGINE=InnoDB AUTO_INCREMENT=11108 DEFAULT CHARSET=utf8 COLLATE=utf8_bin 

我从不带任何mysqli_begin_transaction()的PHP函数flags开始事务,然后开始mysqli_commit()
这里是查询,只有在得到答复的情况下,首先进行UPDATE

UPDATE comment SET replies=replies+1 WHERE com_id = ?; 

INSERT INTO comment (com_p_id,com_cont,com_user,com_us_id,reply_id,replies,noti_reply) VALUES (?,?,?,?,?,0,?);  

UPDATE posts SET post_comm=post_comm+1, trend = @addtrend := trend+2, post_b_id = @thisblog := post_b_id WHERE post_id = ?;

保存@variables是为了在提交后做的不太重要的事情。

2 个答案:

答案 0 :(得分:1)

我认为,简单的INSERT不会阻止其他插入的时间超过插入时间。 AUTO_INC locks不会在整个交易时间内被保留。

但是,如果两个事务尝试像下面的语句中那样更新同一行(两次回复同一条评论)

UPDATE comment SET replies=replies+1 WHERE com_id = ?

第二个必须等待直到第一个被提交。您需要该锁以使计数(回复)保持一致。

我认为您所能做的就是保持交易时间尽可能短。例如,您可以在开始事务之前准备所有语句。但这只是几毫秒。如果传输文件可能需要40秒钟,那么在数据库事务打开时不应该这样做。在开始事务之前,请先传输文件,然后使用表示操作未完成的名称进行保存。您也可以将它们保存在不同的文件夹中,但是在同一分区上。然后,在运行事务时,您只需要重命名文件,这不需要花费很多时间。您可以不定期清理并删除未重命名的文件。

答案 1 :(得分:1)

所有写操作都以类似的方式工作-它们锁定执行语句(直到可能通过COMMIT关闭事务之前接触(或可能接触)的ROLLBACKSELECT...FOR UPDATESELECT...WITH SHARED LOCK也参与其中。

发生写操作时,将完成死锁检查。

在某些情况下,存在“间隙”锁定。 com_id恰好是表格中的最后一个ID吗?

您是否遗漏了需要SELECTs的任何FOR UPDATE