Существует веб-приложение (Win7x64, MS Sql Server 2012, Apache 2.4, PHP 5.6, Yii 1.1).
Около сотни пользователей постоянно наполняют одну таблицу. В случае, если разные пользователи в одно и тоже время произвели вставку строки, первому возвращается ID вставленной строки второго и дальнейшие действия, например сохранение истории изменений, ведется с неверным ID.
Yii использует PDO, в частности метод lastInsertId для получения айдишника, но описания подобной проблемы в интернете не встретил.
Почему такое происходит и как этого избежать?
Заранее спасибо.
upd.
Упрощенно код выглядит так:
//Контроллер
public function actionCreate(){
$model = new Pacient();
$model->attributes = $_POST['Pacient'];
$model->save();
}
//Модель
public function beforeSave(){
if (empty($this->NNAPR)) {
if (!$this->setNNAPR())
return false;
}
return parent::beforeSave();
}
public function afterSave(){
parent::afterSave();
$history = new PacientHistory();
//здесь уже неверный ID
$history->ID_PACIENT = $this->ID;
$history->save();
}
Записи добавляются не только через форму, но и экспортируются xml-файлами, но код используется почти один и тот же. Ситуация повторяется и для файлов и для ручного ввода.
На 2000 добавленных записей в день возникает от 0 до 3 таких ошибок.
upd.2
Для чистоты эксперимента, я создал две новые таблица Collision и CollisionHistory:
CREATE TABLE [dbo].[Collision](
[id] [int] IDENTITY(1,1) NOT NULL,
[uuid] [varchar](50) NULL,
CONSTRAINT [PK_Collision] PRIMARY KEY CLUSTERED
(
[id] ASC
) ON [PRIMARY]
)
CREATE TABLE [dbo].[CollisionHistory](
[id] [int] IDENTITY(1,1) NOT NULL,
[collision_id] [int] NULL,
[uuid] [varchar](50) NULL,
CONSTRAINT [PK_CollisionHistory] PRIMARY KEY CLUSTERED
(
[id] ASC
)
)
На их основе в gii генерю модели.
В модель Collision добавляю код:
public function afterSave(){
parent::afterSave();
$history = new CollisionHistory();
$history->collision_id = $this->id;
$history->uuid = $this->uuid;
$history->save(false);
}
Пишу контроллер
class CollisionController extends CController
{
public function actionTest()
{
for ($i = 0; $i < 1000; $i++) {
$model = new Collision();
$model->uuid = $this->UUIDv4();
$model->save(false);
}
}
//метод с php.net
private function UUIDv4()
{
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
// 16 bits for "time_mid"
mt_rand(0, 0xffff),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand(0, 0x0fff) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand(0, 0x3fff) | 0x8000,
// 48 bits for "node"
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
}
Затем на счет три с коллегой запускаем actionTest каждый со своего компьютера.
В итоге на 2000 инсертов в таблицу Collision 419 повторений collision_id в таблице CollisionHistory.
Тест на чистом PDO дал тот же результат, последний айдишник возвращается для другой записи.