LAST INSERT ID () всегда возвращает 0 (RMySQL) - отдельная проблема подключения

оригинальный пример, как найдено в некоторых в должности

по этому в должности следующие операторы 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

по предложению Б. Н., Джефф Аллен и Quassnoi

адаптировал пример, чтобы он напоминал реальные случаи использования немного больше, чем оригинальный:

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

Ну, это не, действительно ;-)

Я немного погуглил и AFAIU,LAST_INSERT_ID() является "Connection-aware" в том смысле, что одно и то же соединение должно использоваться, если оно должно работать правильно. Тем не менее, я думал, что, назначив объект соединения con я убедился, что действительно такая же связь и используется в каждом из приведенных выше утверждений.

ну, по-видимому, нет ; -) Может ли кто-нибудь помочь мне с некоторыми объяснениями и/или обходными путями? Используя что-то вроде select max(<ID>) from <TABLE> не однако я собираюсь сократить его, поскольку я запускаю несколько потоков, которые одновременно пишут в БД, тем самым испортив поиск идентификатора, если это сделано таким образом.

спасибо!

выводы по состоянию на 2012-04-20

  • спасибо Quassnoi я смог отследить проблему немного больше. Кажется RMySQL функции на самом деле не заботятся о явном conn аргумент, но открывать новые соединения в фоновом режиме каждый раз при подключении к БД. Возможно, для этого тоже есть веские причины. Но знает ли кто-нибудь, как этого избежать?
  • только что связался с Джеффри Хорнером (сопровождающий RMySQL). Похоже, это проблема Windows. Работал на него в Linux: -/

детали подключения

как было предложено Джефф

> 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 ответов


Я нашел рабочее решение здесь. Это также упоминается в ответе 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

вы вставляете NULL значения в столбце первичного ключа. Поскольку вы не можете иметь две строки с одним и тем же ПК, вы, вероятно, не вставляете никаких реальных данных (что также, вероятно, является ошибкой, которую вы хотите поймать). Попробуйте:

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

выполнение, которое должно дать вам два разных значения для last_insert_id.

Edit: неправильно понято. См.здесь подробнее о LAST_INSERT_ID. Пересмотренный ответ: если вы не укажете значение в элементе


мы нашли очень интересное решение:

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

если он не работает, используйте dbClearResult(res) перед отправкой последнего запроса id. У нас все получилось.