function PdoSessionHandler::doWrite
Overrides AbstractSessionHandler::doWrite
File
-
vendor/
symfony/ http-foundation/ Session/ Storage/ Handler/ PdoSessionHandler.php, line 330
Class
- PdoSessionHandler
- Session handler using a PDO connection to read and write data.
Namespace
Symfony\Component\HttpFoundation\Session\Storage\HandlerCode
protected function doWrite(string $sessionId, string $data) : bool {
$maxlifetime = (int) (($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'));
try {
// We use a single MERGE SQL query when supported by the database.
$mergeStmt = $this->getMergeStatement($sessionId, $data, $maxlifetime);
if (null !== $mergeStmt) {
$mergeStmt->execute();
return true;
}
$updateStmt = $this->getUpdateStatement($sessionId, $data, $maxlifetime);
$updateStmt->execute();
// When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in
// duplicate key errors when the same session is written simultaneously (given the LOCK_NONE behavior).
// We can just catch such an error and re-execute the update. This is similar to a serializable
// transaction with retry logic on serialization failures but without the overhead and without possible
// false positives due to longer gap locking.
if (!$updateStmt->rowCount()) {
try {
$insertStmt = $this->getInsertStatement($sessionId, $data, $maxlifetime);
$insertStmt->execute();
} catch (\PDOException $e) {
// Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys
if (str_starts_with($e->getCode(), '23')) {
$updateStmt->execute();
}
else {
throw $e;
}
}
}
} catch (\PDOException $e) {
$this->rollback();
throw $e;
}
return true;
}