I have a table SalesOrders
, which holds the salesOrder
for a particular organization
. Because I track invoices across many organizations, the table also contains an invoice
. Per-organization, the salesOrder
should increment by one, without gaps.
I need to do a
INSERT INTO SalesOrders (...)
VALUES (...
, SELECT MAX(salesOrder) + 1
FROM SalesOrders
WHERE organization = @org)
But this isn't safe without ISOLATION LEVEL SERIALIZABLE
or equivalent locks.
However, when I wrap within a transaction with that isolation level, I'm seeing duplicate values inserted into my table. I don't understand why: the transaction isolation level should prevent this?
The block of code I'm using (PHP PDO) is below.
What reasons could there be for me to see duplicate salesNumbers
in my table, as a result of this query?
$db->query('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
$db->beginTransaction();
$query = '
SELECT MAX(orderNumber) AS number
FROM SalesOrders
WHERE organization = :organization';
$params = array(':organization' => $organizationId);
$statement = $db->prepare($query);
$statement->execute($params);
// Sometimes we have no results at all [no sales for a particular organization]
$existing = $statement->fetchAll();
$newNumber = (sizeof($existing) == 1 ? $existing[0]['number'] + 1 : 1);
$createQuery = 'INSERT INTO SalesOrders (
organization,
orderNumber,
invoice
) VALUES (
:organization,
:number,
:invoice
)';
$createParams = array(
':organization' => $organizationId,
':number' => $newNumber,
':invoice' => $invoiceId
);
$secondStatement = $db->prepare($createQuery);
$secondStatement->execute($createParams);
$db->commit();
More information:
The table in question has ~4300 rows, with 11 duplicated values. For example:
id organization invoice salesOrderNumber
12830 43 12975 705
12831 43 12976 705