I am using Yii2 and ActiveRecord. I have a field called "code" and for each record, it is meant to have a unique value like this: "REC0001", "REC0002", "REC0003" in a sequencial manner.
All works and I can generate a record code as described. However if I refresh my page request fast in a multiple manner (trying to test multiple requests at the same time in a very raw manner hehe), then some of the records end up with the same record code. In other words I found "REC007" a few times.
I generate the code looking at the last code and increase it by one, then I do a while foundFlag == true by checking to see if it already exists in the database.
I am suspecting there is a delay in writing to the database and hence it assumes that it is not there.
Here is a portion of the code:
static function createCode($rec){
if ($rec->code){
return $rec->code;
}
if ($rec->id){ // find it by id if one passed and record exists
$tmpRec = $rec->find()
->where([
'id' => $rec->id,
])
->one();
if ($tmpRec && $tmpRec->code){
return $tmpRec->code;
}
}
$prefix = 'REC';
if (!$prefix){
$prefix = 'REC';
}
$maxDecimals = 12;
$codeLength = $maxDecimals+strlen($prefix);
$query = $rec->find();
$query = $query->where([
'archived' => '0'
]);
// look under an organization if it exists in the model and there is one
if ($rec->hasField('organization_id') && $organization_id){
$query = addQueryWhere($query, [
'organization_id' => $organization_id,
]);
}
$query = addQueryWhere($query, [
'LENGTH(code)' => $codeLength*1,
]);
$query = $query->orderBy('code desc');
$lastRec = $query->one();
$tmpNumber = 0;
if ($lastRec && $lastRec->id){
// check what it returns
$tmpNumber = str_replace($prefix, '', $lastRec->code);
}
$tmpNumber++;
$leftDecimals = $maxDecimals - strlen($tmpNumber.'');
for ($k=0; $k <= $leftDecimals-1 ; $k++){
$tmpNumber = '0'. $tmpNumber;
}
$ret = $prefix . $tmpNumber;
return $ret;
}
public function generateCode($rec){
$foundFlag = true;
$break = 1000; // safe break point - no continuous loop
$cnt = 0;
$code = static::createCode($rec);
while ($foundFlag === true || $cnt < $break){
$tmpRec = $rec->find()
->where([
'code' => $code,
])
->one();
if (!$tmpRec->id){
$foundFlag = false;
break;
}
$time = getCurrentTimestamp();
$code = static::createCode($rec);
$cnt++;
}
$ret = $code;
return $ret;
}
So I simply call: $this->code = $this->generateCode(); Like I said it does work in generating the code, but it creates duplicates when it shouldn't!
Thank you for your assistance.