[
https://issues.apache.org/jira/browse/OFBIZ-3557?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13040315#comment-13040315
]
Bruno Brandmeier commented on OFBIZ-3557:
-----------------------------------------
Hi all,
why not using a lock table like this (example in c#):
c_Lock mylock = new c_Lock("rechnungs_nr");
mylock.use_lock();
int nur_rechnungs_nr = mylock.increment_counter();
mylock.open_lock();
class c_Lock
{
string name = "";
string lock_closed_by = "";
int lock_counter = 0;
bool can_use_lock_now = false;
string unique_id = "";
MySqlConnection conn_shop = null;
c_BB_Shop bb_shop = new c_BB_Shop();
string sql_string = "";
MySqlDataAdapter da = null;
System.Data.DataTable dt_remote = null;
DataRow row_remote = null;
MySqlCommand cmd = null;
BB_Gen.c_BB_Gen bb_gen = new BB_Gen.c_BB_Gen();
public c_Lock(string feldname)
{
name = feldname;
if (name == "")
{
MessageBox.Show("Feldname wurde nicht übergeben");
}
else
{
conn_shop = bb_gen.conn_open(bb_shop.g_connectionstring_shop);
read_lock();
}
Random zufallszahlen = new Random();
unique_id =
zufallszahlen.NextDouble().ToString().Substring(2).PadRight(18,
Convert.ToChar("0"));
}
public bool use_lock()
{
int start_zeit = 0;
int schloss_geschlossen_seit = 0;
int max_lock_lease = 10;
int aktuelle_zeit = 0;
bool result = false;
if (row_remote["lock_type"].ToString() != "undefined")
{
start_zeit = bb_gen.unix_timestamp();
while ((result = close_lock()) == false)
{
aktuelle_zeit = bb_gen.unix_timestamp();
schloss_geschlossen_seit =
int.Parse(row_remote["lock_closed_since"].ToString());
if (((aktuelle_zeit - start_zeit) > max_lock_lease) &&
((aktuelle_zeit - schloss_geschlossen_seit) > max_lock_lease))
{
crack_lock();
break;
}
else
{
Thread.Sleep(1000);
read_lock();
}
}
}
else
{
result = false;
}
return result;
}
public void open_lock()
{
if (can_use_lock_now == true)
{
sql_string = "UPDATE locks SET
lock_status='unlocked',lock_closed_by='',lock_closed_since='0' WHERE Lock_ID='"
+ row_remote["Lock_ID"].ToString() + "';";
cmd = new MySqlCommand(sql_string, conn_shop);
int ergebnis = cmd.ExecuteNonQuery();
cmd.Dispose();
if (ergebnis == 1)
{
lock_closed_by = "";
can_use_lock_now = false;
}
}
conn_shop.Close();
conn_shop.Dispose();
}
private bool crack_lock()
{
bool result_var = false;
sql_string = "UPDATE locks SET
lock_status='locked',lock_closed_by='" + unique_id + "' WHERE Lock_ID='" +
row_remote["Lock_ID"].ToString() + "';";
cmd = new MySqlCommand(sql_string, conn_shop);
int ergebnis = cmd.ExecuteNonQuery();
cmd.Dispose();
if (ergebnis == 1)
{
lock_closed_by = unique_id;
can_use_lock_now = true;
result_var = true;
}
else
{
result_var = false;
}
return result_var;
}
public int increment_counter()
{
int return_var = 0;
if (can_use_lock_now == true && row_remote["lock_type"].ToString()
== "counter")
{
sql_string = "SELECT lock_counter FROM locks WHERE Lock_ID='" +
row_remote["Lock_ID"].ToString() + "';";
cmd = new MySqlCommand(sql_string, conn_shop);
int result = int.Parse(cmd.ExecuteScalar().ToString());
cmd.Dispose();
if (result == 0)
{
return_var = 0;
}
else
{
int lock_counter_incremented = result;
lock_counter_incremented++;
sql_string = "UPDATE locks SET lock_counter='" +
lock_counter_incremented.ToString() + "' WHERE Lock_ID='" +
row_remote["Lock_ID"].ToString() + "';";
cmd = new MySqlCommand(sql_string, conn_shop);
int ergebnis = cmd.ExecuteNonQuery();
cmd.Dispose();
if (ergebnis == 0)
{
return_var = 0;
}
else
{
lock_counter = lock_counter_incremented;
return_var = lock_counter_incremented;
}
}
}
else
{
return_var = 0;
}
return return_var;
}
private bool close_lock()
{
bool result_var = false;
string object_identifier = unique_id;
sql_string = "UPDATE locks SET
lock_status='locked',lock_closed_by='" + unique_id + "', lock_closed_since='" +
bb_gen.unix_timestamp().ToString() + "' WHERE Lock_ID='" +
row_remote["Lock_ID"].ToString() + "' AND lock_status='unlocked';";
cmd = new MySqlCommand(sql_string, conn_shop);
int ergebnis = cmd.ExecuteNonQuery();
cmd.Dispose();
if (ergebnis == 0)
{
result_var = false;
}
else
{
sql_string = "SELECT lock_closed_by FROM locks WHERE Lock_ID='"
+ row_remote["Lock_ID"].ToString() + "';";
cmd = new MySqlCommand(sql_string, conn_shop);
string object_identifier_aus_db =
cmd.ExecuteScalar().ToString();
cmd.Dispose();
if (object_identifier_aus_db != object_identifier)
{
read_lock();
result_var = false;
}
else
{
lock_closed_by = object_identifier;
can_use_lock_now = true;
result_var = true;
}
}
return result_var;
}
private bool read_lock()
{
bool return_val = false;
sql_string = "SELECT * FROM locks where name='" + name + "';";
da = new MySqlDataAdapter(sql_string, conn_shop);
dt_remote = new System.Data.DataTable();
da.Fill(dt_remote);
if (dt_remote.Rows.Count == 1)
{
row_remote = dt_remote.Rows[0];
return_val = true;
}
return return_val;
}
}
Bruno
> Enforced sequence does not work with concurrent access
> ------------------------------------------------------
>
> Key: OFBIZ-3557
> URL: https://issues.apache.org/jira/browse/OFBIZ-3557
> Project: OFBiz
> Issue Type: Bug
> Components: framework
> Affects Versions: Release Branch 09.04, SVN trunk
> Reporter: Wickersheimer Jeremy
> Attachments: OFBIZ-3557-1.patch, OFBIZ-3557-2.patch
>
>
> There is a fundamental issue with enforced sequences (for orders, invoices,
> etc ..) and concurrency.
> For example if two users are creating an order at the same time one of them
> will see the creation fail with a PK error. The problem is that the
> "getNextXXXId" rely on the party accounting preference entity, but there is
> absolutely no guarantee that the last number in the sequence gets updated
> before another service can read it.
> This is at best very annoying when used only internally but may be
> unpractical for e-commerce sites.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira