Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用子选择插入-原子操作?_Java_Mysql_Transactions_Atomic - Fatal编程技术网

Java 使用子选择插入-原子操作?

Java 使用子选择插入-原子操作?,java,mysql,transactions,atomic,Java,Mysql,Transactions,Atomic,我知道,mysql支持自动增量值,但不支持依赖的自动增量值 i、 e.如果您有这样一张桌子: id | element | innerId 1 | a | 1 2 | a | 2 3 | b | 1 如果插入另一个b-元素,则需要自己计算innerId(插入除外为“2”) 有一个数据库支持这样的东西吗 实现这种行为的最佳方式是什么?我不知道元素的数量,所以我不能为它们创建专用表,在那里我只能驱动一个id (示例已简化) 应该实现的目标是,任何元素“

我知道,mysql支持自动增量值,但不支持依赖的自动增量值

i、 e.如果您有这样一张桌子:

id | element | innerId
1  | a       | 1
2  | a       | 2
3  | b       | 1
如果插入另一个
b
-元素,则需要自己计算innerId(插入除外为“2”)

  • 有一个数据库支持这样的东西吗
实现这种行为的最佳方式是什么?我不知道元素的数量,所以我不能为它们创建专用表,在那里我只能驱动一个id

(示例已简化)

应该实现的目标是,任何元素“类型”(在数字未知的情况下,
可能是infine-1
都应该有自己的、无间隙的id

如果我想用像

INSERT INTO 
  myTable t1 
   (id,element, innerId)
   VALUES
   (null, 'b', (SELECT COUNT(*) FROM myTable t2 WHERE t2.element = "b") +1)

这在所有情况下都会返回预期结果吗?我的意思是它可以工作,但是并发性如何呢?带有子选择的插入是否仍然是原子的,或者是否会有一个szenario,其中两个插入将尝试插入相同的id?(特别是在事务性插入挂起的情况下?)

使用编程语言(如Java)来实现这一点会更好吗?还是尽可能靠近数据库引擎来实现这一逻辑更容易

因为我使用聚合来计算下一个innerId,所以我认为使用
SELECT…FOR UPDATE
无法避免其他事务具有挂起提交的问题,对吗

注:我可以使用ofc。只需在
(element,innerId)
上使用唯一的键约束来强制插入-从每个元素的当前最大值开始-直到没有foreignKey冲突-但是没有更好的方法吗

根据我的例子,
innerId和element
上有一个复合主键,这是可能的。但根据这一点,它只适用于MyIsam(我有InnoDB)


现在我更困惑了。我尝试使用两个不同的php脚本插入数据,使用上面的查询。虽然脚本一有15秒的“睡眠”时间,以便允许我调用脚本二(应该模拟并发修改),但使用一个查询时,结果是正确的

(附言:
mysql(?!i)
-仅用于快速调试的函数)

基础数据:

脚本1:

mysql_query("START TRANSACTION");
mysql_query("INSERT INTO insertTest (id, element, innerId, fromPage)VALUES(null, 'a', (SELECT MAX(t2.innerID) FROM insertTest t2 WHERE element='a') +1, 'page1')");

sleep(15);

//mysql_query("ROLLBACK;");
mysql_query("COMMIT;");
脚本2:

//mysql_query("START TRANSACTION");
mysql_query("INSERT INTO insertTest (id, element, innerId, fromPage)VALUES(null, 'a', (SELECT MAX(t2.innerID) FROM insertTest t2 WHERE element='a') +1, 'page2')");
//mysql_query("COMMIT;");
我本以为
page2
insert会在
page1
insert之前发生,因为它运行时没有任何事务。但事实上,page1 insert是先发生的,导致第二个脚本也延迟了大约15秒

(忽略AC Id,播放一段时间)

在第一个脚本上使用
Rollback
时,第二个脚本仍会延迟15秒,然后选择正确的
innerId

所以

  • 事务处于活动状态时阻止非事务性插入
  • 带有子选择项的插入似乎也被阻止
  • 因此,在结尾处,带有子选择的Insert似乎是一个原子操作?或者为什么第二页的
    SELECT
    会被其他页面阻止
在单独的非事务性语句中使用SELECT和insert(第2页,模拟并发修改):

导致我试图避免的错误:

那么,当每次修改都是一个查询时,为什么它在并发szenario中工作?是带有子选择原子的插入?好吧,所有(或几乎所有)数据库都支持根据规则计算
innerid
的必要功能。它被称为触发器,特别是插入前触发器

您的特定版本在多用户环境中无法一致工作。很少(如果有的话)数据库在启动insert时会在表上生成读取锁。这意味着两条insert语句非常接近地发出,将为
innerid
生成相同的值

出于并发性考虑,您应该在数据库中使用触发器而不是在应用程序端执行此计算

您总是可以在需要时计算
innerid
,而不是在插入值时。这在计算上很昂贵,需要一个
order by
(使用变量)或者相关子查询。其他数据库支持窗口/分析函数,使这样的计算更易于表达。

从我在这里读到的内容来看:您的查询似乎是原子的。我用InnoDB在MySQL上对其进行了测试,有4个不同的程序试图执行每个查询100000次。之后,我能够创建一个组合的Unique键在(element,innerid)上,它工作得很好,所以它似乎没有生成重复项。但是我得到了:

尝试获取锁时发现死锁

<>你可能想考虑这个

编辑:看来我可以通过将SQL更改为

插入测试(id、元素、innerId) 值(null,“b”,
(从测试t2中选择Count(*),其中元素='b'用于更新()+1);

Thx作为您的答案。是的,可以计算innerID,基本上它是某一类型元素中的行号。问题是,(我讨厌那个句子)客户希望在复合模式布局中使用大量元素(限制为n=5)。对新数据的期望大约是每天数千次插入,因此存储生成的
子id
会更好-性能方面,当您必须找到元素125.5685.125.2145.3369时-因为我可以从第5个innerId列(其他列)中选择innerId 3369请查看我的更新。我还玩过并发插入,它看起来像是一个带有subselects I的插入
$nextId = mysql_query("SELECT MAX(t2.innerID) as a FROM insertTest t2 WHERE element='a'");
$nextId = mysql_fetch_array($nextId);
$nextId = $nextId["a"] +1;
mysql_query("INSERT INTO insertTest (id, element, innerId, fromPage)VALUES(null, 'a', $nextId, 'page2')");