mysql - MySQL(innodb)中同时插入

标签 mysql innodb database-concurrency

假设我们在数据库 Test 中有一个表 t_log。 t_log 如下所示

create table `t_log`(
`F_log_id` bigint(20) not null AUTO_INCREMENT,
`F_trans_id` bigint(20) not null,
`F_action` tinyint(3) not null,
primariy key(`F_log_id`)
)engine=innodb

假设F_action字段只能取几个特定值,如1和2。对于F_action=1条记录,对应的F_trans_id必须不同于彼此。而对于 F_action=2 条记录,对应的 F_trans_id 可以采用相同的值。

例如表中类似以下的记录应该是有效的

F_log_id | F_action | F_trans_id
  1            1          1001
  2            2          1002
  3            2          1002

但是像下面这样的记录应该无效

F_log_id | F_action | F_trans_id
  1            1          1001
  2            1          1001
  3            2          1002

由于我们对F_trans_id的唯一限制取决于F_action的具体值,因此我们不能仅仅在F_trans_id和F_action上建立唯一索引。

为了保持一致性,将记录插入到 t_log 中被放入这样的事务中

start_transaction()
select and check if valid
do inserting
commit()

但是在高并发环境下,可能有两个插入事务几乎同时到达,比如都进入了start_transaction(),假设两条记录都是(F_action=1, F_trans_id=222),当select and检查,发现两条记录都有效并插入它。那么t_log将会有两条无效记录。

有什么好的方法可以防止这种无效记录吗?谢谢。

最佳答案

根据需要使用算术生成唯一值:

  • 创建一个新列,例如action_hash int
  • (F_trans_id, action_hash)上创建唯一索引
  • 创建一个触发器,在需要时使用不同的值填充 action_hash

在您的示例中,我能想到的最简单的事情是:

new.action_hash = new.F_log_id * (new.F_action - 1)

F_action1时,该值为零,这要求F_trans_id是唯一的,但其他情况下则不然。

关于mysql - MySQL(innodb)中同时插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25032888/

相关文章:

hibernate (JPA): how to handle StaleObjectStateException when several object has been modified and commited

database - PostgreSQL - MVCC(多版本并发控制) - 何时获取实际锁?

mysql - SQL 中的唯一 ID 主键 - 可以自动分配吗

MySQL - 选择按字母顺序排在第一位的名称

mysql - 我可以通过 SSH 隧道使用 Navicat 连接到 mysql,但无法使用 shell 或 java 连接

MySQL 和外键

MySQL:单个表中的死锁 UPDATE ... WHERE

c++ - 带有 MySQL Connector stmt->executeQuery() 错误的 VS Express 2013 C++

MySql server 5.0.96 有时挂起

mysql - mysql出现 "[ERROR] InnoDB: Operating system error number 87 in a file operation"怎么解决?