php - 多个浏览器连接获取相同的 DB 对象

标签 php mysql

运行两个并发脚本,我想按顺序访问数据库,以便每个的自动增量主键是顺序的。即同时运行它们(实例 A 和实例 B)将导致

1-A, 2-A, 3-A, 1-B, 2-B, 3-B

但是,目前我得到
1-A, 1-B, 2-A, 2-B ,3-A ,3-B

在事务和锁定表没有像我预期的那样工作之后,我做了一些更深入的研究,看起来两个脚本(即使在不同的浏览器中运行)都获得了相同的连接。因此,由于它们都在同一 session 中,因此不会阻止另一个。我能做些什么来强制他们获得不同的连接(更改为 mysqli 或 PDO 不是一种选择,因为这是一个现有系统)?

Chrome 合金:
object(DB_mysql)#10 (26) {
  ["phptype"]=>
  string(5) "mysql"
...

火狐
object(DB_mysql)#10 (26) {
  ["phptype"]=>
  string(5) "mysql"
...

DB 创建是使用下面的 DSN 字符串完成的。 (里面还有一些其他的逻辑)
mysql://root:@127.0.0.1/XXX?new_link=true

查询运行:
LOCK TABLES xxxx write
SET autocommit=0
TRANSATION START
>>insert 1
>>insert 2
>>insert 3
COMMIT
UNLOCK TABLES

两个标签同时刷新:
表 1:
  [0]=>
  int(56335766)
  [1]=>
  int(56335768)
  [2]=>
  int(56335770)

表 2:
array(3) {
  [0]=>
  int(56335765)
  [1]=>
  int(56335767)
  [2]=>
  int(56335769)
}

正如数据所示,尽管表被锁定,但数据是相互交织的。

最佳答案

问:为什么锁定不起作用?

答:根据问题的更新,显示SQL语句的顺序:

 LOCK TABLES xxx WRITE  
 START TRANSACTION

问题是START TRANSACTION正在释放锁。

此行为记录在 MySQL 引用手册中

引用:http://dev.mysql.com/doc/refman/5.6/en/lock-tables.html

Rules for lock release

If a session begins a transaction (for example, with START TRANSACTION), an implicit UNLOCK TABLES is performed, which causes existing locks to be released. (For additional information about the interaction between table locking and transactions, see Section 13.3.5.1, “Interaction of Table Locking and Transactions”.



下面原始问题的原始答案

问:我可以做些什么来强制他们获得不同的连接?

答:我想你可能在那里吠错了树。很可能每个人都使用不同的数据库连接。

您显示的值 2-A , 2-B , 3-A 似乎是字符串值。

如果你做 SELECTORDER BY在这些字符串值上,行将按照您显示它们返回的顺序返回。没有 ORDER BY , MySQL 可以自由地以它想要的任何顺序返回行。如果 MySQL 使用索引返回行,而不执行排序操作,我们(几乎总是)观察到返回的行以与索引中出现的行相同的顺序返回。

如果您依赖于 AUTO_INCREMENT列的属性,不会将相同的值分配给两个不同的行(除非您使用的是 MyISAM 并且 AUTO_INCREMENT 列不是索引中的前导列...)

除此之外,两行不可能获得相同的 auto_increment 值。

或者,你在数据库表中得到的实际上更像是
  auto_id  byclient
  -------  --------
    14156  A
    14157  B
    14158  A
    14159  B
    14160  A
    14161  B
AUTO_INCREMENT属性在表上的列上,而不是“每个数据库连接”。插入行的两个(或更多)并发 session 可以执行“交错”值的操作。他们不必使用相同的数据库连接。

为了防止其他数据库连接同时对表执行 INSERT,您需要实现一种机制来实现这一点。在数据库层面,可以使用一些并发杀表锁。但是这些只保留到它们被释放,或者在数据库连接期间。如果您断开与数据库的连接,这些锁就会消失。

因此,如果两个单独的浏览器间歇性地调用同一个 PHP 页面,那对您没有帮助。即使您确实有办法为每个浏览器 session 获取单独的数据库连接。

我强烈怀疑您正在搅动数据库连接,为每次执行 PHP 脚本建立一个新的数据库连接。

(我认为您可能对使用相同的数据库连接大喊大叫。使用多个数据库连接您会得到相同的行为。)

跟进

我认为你问错了问题。为什么您需要“按顺序”设置 AUTO_INCREMENT id 值?如果这是实际要求,那么可能是 AUTO_INCREMENT不会是问题的合适解决方案。 (似乎您可能正在尝试让 AUTO_INCREMENT 执行它不适合的任务。在某些配置中,您不能保证 AUTO_INCREMENT 值将按照插入行的顺序递增。)

而不是要求 AUTO_INCREMENT 值是连续的(这真的是一个要求),我会备份,并考虑真正的要求是什么。也许识别插入每一行的“ session ”(让每个 session 在表中的一列中存储一个值,以及客户端为该 session 分配的升序整数值。然后你不必关心什么AUTO_INCREMENT 值被赋值:
 auto_id  session_id  seq_   
 -------  ----------  ---- 
   75322  3e45bf4        1 
   75323  3e45bf4        2 
   75327  3e45bf4        3 
   75325  3e45bf4        4 
   75324  f51113e        1 
   75326  f51113e        2 
   75322  f51113e        3 

关于php - 多个浏览器连接获取相同的 DB 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31174332/

相关文章:

javascript - 为什么单击按钮时会运行两个函数而不是一个?

mysql - 对 GROUP BY HAVING 的结果求和

java - Spring Boot 应用程序未部署 - 无法创建 XADataSource 实例

php - 无法使用 php 从 mysql 获取数据到 html 表,显示内部服务器错误

php - yii框架中的多个文件上传,保存图像之前显示预览

php - 前 30 天到期后,如何取消每月定期费用?

mysql - 如何跨多个服务器nodejs和socket.io存储socket.id

php - mysqli_fetch_array 不保存完整的下拉数据

php - 使用 GET 执行数据库操作的快速、简单且安全的方法

php - 验证散列密码的长度(注册)php