LAST_INSERT_ID()始终返回0(RMySQL) - 单独的连接问题

时间:2012-04-20 12:39:23

标签: mysql r rmysql last-insert-id

在某些post

中找到的原始示例

根据这个post,下面的SQL语句应该给我一个向量 1, 2, 2, 2, 2最后:

require("RMySQL")
con <- dbConnect(
    dbDriver("MySQL"),
    db="your_db",
    user="your_user",
    password="your_pw", 
    host="localhost"
)
> con
<MySQLConnection:(6640,122)> 
> dbSendQuery(con, "DROP TABLE IF EXISTS t;")
<MySQLResult:(6640,122,0)> 
> dbSendQuery(con, "CREATE TABLE t (i INT NOT NULL AUTO_INCREMENT PRIMARY KEY);")
<MySQLResult:(6640,122,1)> 
> dbSendQuery(con, "INSERT INTO t VALUES(NULL);")
<MySQLResult:(6640,122,2)> 
> dbGetQuery(con, "SELECT LAST_INSERT_ID() FROM t;")
  LAST_INSERT_ID()
1                0
> dbSendQuery(con, "INSERT INTO t VALUES(NULL),(NULL),(NULL);")
<MySQLResult:(6640,122,3)> 
> dbGetQuery(con, "SELECT LAST_INSERT_ID() FROM t;")
  LAST_INSERT_ID()
1                0
2                0
3                0
4                0

按照N.B.Jeff AllenQuassnoi

的建议

改编示例使其与实际用例相比原始用例更多:

dbSendQuery(con, "DROP TABLE IF EXISTS t;")
dbSendQuery(con, paste("CREATE TABLE t", 
    "(i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, x INT);"))
> dbGetQuery(con, "SELECT CONNECTION_ID();")
  CONNECTION_ID()
1          673490
dbSendQuery(con, "INSERT INTO t SET x=1;")
> dbGetQuery(con, "SELECT CONNECTION_ID();")
  CONNECTION_ID()
1          673491
> dbGetQuery(con, "SELECT LAST_INSERT_ID();")
  LAST_INSERT_ID()
1                0
> dbGetQuery(con, "SELECT CONNECTION_ID();")
  CONNECTION_ID()
1          673493
> dbGetQuery(con, "SELECT LAST_INSERT_ID();")
  LAST_INSERT_ID()
1                0
dbSendQuery(con, "INSERT INTO t SET x=2;")
> dbGetQuery(con, "SELECT LAST_INSERT_ID();")
  LAST_INSERT_ID()
1                0
> dbGetQuery(con, "SELECT * FROM t;")
  i x
1 1 1
2 2 2

嗯,事实并非如此;-)

我已经google了一点,AFAIU,LAST_INSERT_ID()是“连接感知”,因为如果要正常工作,必须使用相同的连接。但是,我认为通过将连接对象分配给con,我确保在上面的每个语句中确实使用了相同的连接

嗯,显然不是;-)任何人都可以通过一些解释和/或解决方法帮助我吗? 但是,使用像select max(<ID>) from <TABLE>这样的东西并不会削减它,因为我正在运行多个同时写入数据库的线程,因此如果这样做就会搞乱ID检索。

谢谢!

截至2012-04-20的结果

  • 感谢Quassnoi我能够更多地追踪问题。似乎RMySQL函数并不真正关心显式conn参数,但每次连接到数据库时都会在后台打开新连接。这也可能是一些很好的理由。然而,有谁知道如何避免这种情况?
  • 刚刚联系过Jeffrey Horner(RMySQL包的维护者)。似乎这是一个Windows问题。在Linux上为他工作: - /

连接详情

根据Jeff

的建议
> dbGetInfo(con)
$host
[1] "localhost"

$user
[1] "your_user"

$dbname
[1] "your_db"

$conType
[1] "localhost via TCP/IP"

$serverVersion
[1] "5.5.20"

$protocolVersion
[1] 10

$threadId
[1] 673489

$rsId
$rsId[[1]]
<MySQLResult:(6640,171,3)> 


> dbGetInfo(dbDriver("MySQL"))
$drvName
[1] "MySQL"

$connectionIds
$connectionIds[[1]]
<MySQLConnection:(6640,149)> 

$connectionIds[[2]]
<MySQLConnection:(6640,112)> 

$connectionIds[[3]]
<MySQLConnection:(6640,171)> 


$fetch_default_rec
[1] 500

$managerId
<MySQLDriver:(6640)> 

$length
[1] 16

$num_con
[1] 3

$counter
[1] 179

$clientVersion
[1] "5.5.20"

> dbListConnections(dbDriver("MySQL"))
[[1]]
<MySQLConnection:(6640,149)> 

[[2]]
<MySQLConnection:(6640,112)> 

[[3]]
<MySQLConnection:(6640,171)> 

3 个答案:

答案 0 :(得分:2)

我找到了一个有效的解决方案here。在stephan mc的回复中也提到过,但作为第二种选择。第一个不适合我,所以我认为这可能值得更多突出。

无论如何,诀窍是在dbClearResult()INSERT之间运行SELECT LAST_INSERT_ID()

> library("RMySQL")
> con <- dbConnect(MySQL())
> dbSendQuery(con, "DROP TABLE IF EXISTS t;")
> dbSendQuery(con, "CREATE TABLE t (i INT NOT NULL AUTO_INCREMENT PRIMARY KEY);")
> res <- dbSendQuery(con, "INSERT INTO t VALUES (NULL);")

# doesn't work:
> dbGetQuery(con, "SELECT LAST_INSERT_ID();")
  LAST_INSERT_ID()
1                0

# works:
> dbClearResult(rs)
> dbGetQuery(con, "SELECT LAST_INSERT_ID();")
  LAST_INSERT_ID()
1                1

答案 1 :(得分:0)

您正在将NULL值插入主键列。由于您不能拥有两个具有相同PK的行,因此您可能实际上并未插入任何实际数据(这也可能是您想要捕获的错误)。尝试:

dbSendQuery(con, "INSERT INTO t VALUES(5);")

执行它应该为last_insert_id提供两个不同的值。

编辑:被误解了。有关LAST_INSERT_ID的详细信息,请参阅here。修改后的答案:如果您未在AUTO_INCREMENT列中指定值,,则应返回LAST_INSERT_ID值。在这种情况下,请尝试:

INSERT INTO t DEFAULT VALUES

答案 2 :(得分:0)

我们找到了一个非常有趣的解决方案:

res <- dbSendQuery(con, "INSERT INTO t VALUES (5);")
res <- dbSendQuery(con, "SELECT LAST_INSERT_ID();")
fetch(res)

如果不起作用,请在发送最后一个ID请求之前使用dbClearResult(res)。对我们来说,它已经成功了。