[ 
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

Reply via email to