I have an invoicing database.
Every invoice has a serial number, a serial number for each period (year or quarter), for example 2005/16, 2005/17, 2004/3,2004/4
In another database these serialnumbers are stored.
There are 2 fields in this database: period and number
To set the number I tried the following method:
//lock the related serial
var success = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
//if record is locked, loop untill lock is released
while ( !success )
{
var success = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
}
//get the number
invoicenumber = invoice_to_invoice_yearnumbers.invoicenumber
//set the serial+1
invoice_to_invoice_yearnumbers.invoicenumber = invoice_to_invoice_yearnumbers.invoicenumber + 1
controller.saveData()
databaseManager.releaseAllLocks()
This does not work properly, sometimes I get a message “Record is locked”. This message should not appear, the system has to wait until the lock of another user is released and than continue.
Any hints? Is there a much better way?
In Filemaker I used to do it this way:
Set Error Capture [ On ]
Allow User Abort [ Off ]
Loop
Go to Field [ nr ]
Exit Loop If [ Status( CurrentError) = 0 ]
End Loop
Set Field [ nr, nr+1 ]
Stored procedures are safe, but depend on the database. That’s why I don’t use them. Once your customer insists on using Oracle or whatever, you go through all your procedures…
What you can do is check if there is a lock or not. If the result is true (there is a lock) you can either report this to the user and let the user decide to try again or you do a loop. The check would look like this:
var success = databaseManager.acquireLock(relation_name, 0);
if (!success) {
plugins.dialogs.showWarningDialog(bla bla);
return;
}
var invoicenumber = relation_name.number;
relation_name.number += 1;
databaseManager.releaseAllLocks();
return invoicenumber;
var success = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
if (!success)
{
application.sleep(2000);
}
var successs = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
if (!successs)
{
application.sleep(2000);
}
var successss = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
if (!successss)
{
application.sleep(2000);
}
var successsss = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
if (!successsss)
{
application.sleep(2000);
}
var successssss = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
if (!successssss)
{
plugins.dialogs.showErrorDialog( “Error”, “The system is busy at the moment. Please try again.”, “OK”)
return;
}
invoicenumber = invoice_to_invoice_yearnumbers.invoicenumber
invoice_to_invoice_yearnumbers.invoicenumber += 1;
controller.saveData()
databaseManager.releaseAllLocks();
And it works fine!
Servoy crew, is this “Catholic”???
Stef:
//lock the related serial
var success = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
//if record is locked, loop untill lock is released
while ( !success )
{ var success = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
}
I think “var” in bold is the problem… you redefine success, seems strange to me
suggestion:
var success = false;
for (var t = 0 ; t < 5 ; t++) //try max 5 times
{
success = databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1);
if (success)
{
break;
}
else
{
application.sleep(2000);
}
}
if (!success) //5 times failed
{
plugins.dialogs.showErrorDialog( "Error", "The system is busy at the moment. Please try again.", "OK")
return;
}
invoicenumber = invoice_to_invoice_yearnumbers.invoicenumber
invoice_to_invoice_yearnumbers.invoicenumber += 1;
controller.saveData()
databaseManager.releaseAllLocks();
Issue confirmed, there appears to be a locking problem in some specific situations, we will release a fix asap.
Additionally here’s a shorter way to get your lock:
var theCounter = 1
while(!databaseManager.acquireLock(invoice_to_invoice_yearnumbers,-1))
{
application.sleep(1000)
theCounter++
if(theCounter>60) // stop if 60 times you attempted to lock
{
//showdialogcode here that says that it's not going to happen this time
return
}
}
invoicenumber = invoice_to_invoice_yearnumbers.invoicenumber
invoice_to_invoice_yearnumbers.invoicenumber += 1;
controller.saveData()
databaseManager.releaseAllLocks();
I have use a variation on Jan’s method. And tranformed it into a global method, becoz we have 4 counters, on different tables. menu_to_menu is a table with only 1 record always.
But some of our client still complain about double numbers.
var deTeller = arguments[0];
if (deTeller!='dos' && deTeller!='of' && deTeller!='nota' && deTeller!='roy'){
return false;
}
var aa = {'dos':'dossier nummer','roy':'royementnummer','nota':'notanummer','of':'offertenummer'};
var bb = {'dos':'dossierlaatstenummer','roy':'royaktenlaatstenummer','nota':'factuurlaatstenummer','of':'offertelaatstenummer'};
var theCounter = 1
while(!databaseManager.acquireLock(menu_to_menu,-1))
{
application.sleep(500)
theCounter++;
if(theCounter>60) // stop if 60 times you attempted to lock
{
globals.messageWarning('Het is niet gelukt om '+aa[deTeller]+' op te hogen!\nNeem kontakt op met Devoon','OK',null);
return false;
}
}
var lastNr = eval('menu_to_menu.'+bb[deTeller]);
eval('menu_to_menu.'+bb[deTeller]+'+=1');
controller.saveData();
databaseManager.releaseAllLocks();
return lastNr;
We have client that complain about double numbers. I have checked if people are messing with the counters, but according to the logfile, they didn’t. So somehow this method is failing somewhere.
you are right, I over looked…, but are you sure that all clients are looking at the same records in menu_to_menu related foundset?
BTW why are you locks for sequences? its far more easy to make an sequence table with columns having sequences and use databaseManager.getNextSequence(…) which has far less overhead, all locking is done by Servoy server internally then
Jan Blok:
you are right, I over looked…, but are you sure that all clients are looking at the same records in menu_to_menu related foundset?
Actually the menu table only has 1 record, menu_to_menu is a bit overkill
Jan Blok:
BTW why are you locks for sequences? its far more easy to make an sequence table with columns having sequences and use databaseManager.getNextSequence(…) which has far less overhead, all locking is done by Servoy server internally then
I am not familiar databaseManager.getNextSequence yet…and I saw the method of Jan Aleman a while ago…and implemented it