Непонятки с PDO lastInsertId()

Namistai

Новичок
Привет.

PDO lastInsertId() выдает 0, при определенных обстоятельствах. А именно когда PDO завернут в другой объект и из этой обертки вызывается. Обертка нужна для реконнекта при обрыве, только для этой цели я ее использую. Если вызывать lastInsertId() без обертки, то всё работает как надо и ID выдаются, а из обертки - всегда 0.

Вот код класса обертки:

Код:
class R_PDO    {
   
    protected $pdo_conn;
   
    protected $dsn, $username, $password, $driver_options;
   
   
   
    public function __construct($dsn, $username, $password, $driver_options)    {
       
        $this -> dsn = $dsn;
        $this -> username = $username;
        $this -> password = $password;
        $this -> driver_options = $driver_options;
       
        $this -> connect();
       
    }
   
    public function __destruct()    {
   
        $this -> pdo_conn = null;
   
    }

   
    public function __call($name, array $arguments)    {
       
        try    {
           
            $this -> connection() -> query("SHOW STATUS;") -> execute();
           
           
        }    catch(PDOException $e)    {
           
            if($e->getCode() != 'HY000' || !stristr($e->getMessage(), 'server has gone away')) {
               
                throw $e;
               
            }    else    {
               
                write_logs('R_PDO: connection fail, reconnecting...');
                $this -> reconnect();
                               
               
            }
           
        }
       
       
        return call_user_func_array(array($this -> connection(), $name), $arguments);
       
    }

    protected function connection()    {
       
        return $this -> pdo_conn instanceof PDO ? $this -> pdo_conn : $this -> connect();
               
    }

    public function connect()    {
       
        try    {
                                   
            $this -> pdo_conn = new PDO($this -> dsn, $this -> username, $this -> password, (array)$this -> driver_options);
            $this -> pdo_conn -> setAttribute(PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION);
           
        }    catch(PDOException $e)    {
           
            write_logs($e->getMessage());
            die();
           
        }
       
        return $this -> pdo_conn;
       
    }

    public function reconnect()    {
       
        $this -> pdo_conn = null;
        return $this -> connect();
       
    }

   
   
}

Помогите разобраться.
 

Namistai

Новичок
Я уже кое-что понял

lastInsertId() скидывается в ноль после испольнения комманды

$this -> connection() -> query("SHOW STATUS;") -> execute();

которая всегда исполняется для прозвона базы на обрыв подключения, если эту строку закоментировать, то все нормально становится

почему так, ума не приложу
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
И правда почему так. Когда последний запрос данных не вставил, а ты ожидаешь что там будет ответ не равных 0
 

Namistai

Новичок
И правда почему так. Когда последний запрос данных не вставил, а ты ожидаешь что там будет ответ не равных 0
я думал что lastinsertId выдает id последней вставленной записи где есть автоинкремент и ему не важно что после есть еще запросы не связанные с INSERT

если lastinsertId нужно непременно запускать следующим запросом после INSERT, то фигово конечно
 

Namistai

Новичок
Я разобрался, всем спасибо.
Дело в том что lastInsertId() не совсем адекватно работает, если после INSERT с автоинкрементом вам нужно узнать с каким ID добавлена запись, то нужно использовать lastInsertId() СРАЗУ после INSERT, иначе он будет возвращать 0, не важно что вы между делом используете запросы не связанные с INSERT.

Альтернатива - использование стандартной функции MYSQL - LAST_INSERT_ID()
в этом случае всё работает логично и после добавления записей через INSERT можно давать запросы не связаные с INSERT и получать ID последней записи.
 

Фанат

oncle terrible
Команда форума
осталось только узнать, кому и с какого перепою пришло в голову выполнять команду SHOW STATUS
 

Breeze

goshogun
Команда форума
Партнер клуба
Эээ... я не совсем понял, что значит "НИЧЕГО не делать"? Нам же нужно проверить соединение, для этого нужно послать какой-нибудь запрос.
ты уже делаешь запрос insert, select и т.д., ?зачем перед ним слать какой-то еще?
 

Namistai

Новичок
ты уже делаешь запрос insert, select и т.д., ?зачем перед ним слать какой-то еще?
Для того чтобы если будет дисконнект запрос не ушел в никуда, в моем случае сначала сработает тестовый запрос, и если есть дисконнект то произойдет реконнект и только после этого пойдет рабочий запрос, таким образом мы обеспечиваем стабильную работу в скрипте.
 

Breeze

goshogun
Команда форума
Партнер клуба
try {
request
} catch {
reconnect
request
}

так понятнее?
 

fixxxer

К.О.
Партнер клуба
А теперь все вместе задумаемся, что произойдёт, если была открыта транзакция. :)
 

Breeze

goshogun
Команда форума
Партнер клуба
А теперь все вместе задумаемся, что произойдёт, если была открыта транзакция. :)
для этого надо сначала не делать настолько долгоиграющих транзакций, что вылезает has gone away :)

я обычно такие штуки ловлю, когда по крону что-то атомарное, но в большом количестве считается и случается зависание на каком-то этапе: много селектов, что-то еще внешнее, а потом надо инсерт/апдейт от полученного и он как раз важен. и так в цикле :)

думаю деньги так считать более вредно, чем полезно :)
 

fixxxer

К.О.
Партнер клуба
для этого надо сначала не делать настолько долгоиграющих транзакций, что вылезает has gone away
А в случае рестарта mysqld с libmysql не так же будет? (Проверить негде, везде mysqlnd)
 

Breeze

goshogun
Команда форума
Партнер клуба
она наиболее часто происходит, когда истекает wait_timeout, но коннект открыт остается.
а рестарт рвет коннект, если я не ошибаюсь.
 
Сверху