65.9K
CodeProject 正在变化。 阅读更多。
Home

MySQL 的事务、锁定和表释放

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.20/5 (5投票s)

2004 年 4 月 17 日

3分钟阅读

viewsIcon

101840

downloadIcon

1717

实现一个简单的类来存储多个查询并针对 MySQL 数据库运行。

Sample Image - odbcexecuter.jpg

引言

在我的最后一个项目中,我需要开发一个类,该类可以简化针对我的 MySQL 数据库执行多个查询的操作。 我开发这个类是为了易于使用并且“事半功倍”。 我想在这里展示的是如何

  • 创建 OdbcExecuter 类。

Using the Code

我实现的这个类基于一个 Windows 窗体,该窗体还允许向用户反馈有关事务的信息。 要使用它,您只需将该类添加到您的项目中。 首先添加一个 Windows 窗体并声明一些私有变量

私有变量

public class OdbcExecuter : System.Windows.Forms.Form
{
    // the string array with queries
    private string[] QueryCollection = new string[1];
    // the connection string
    private string connstring;
    // the message show to user while executing
    private string waitmessage = "EXECUTING THE QUERIES";
    // total commands to execute
    private int nCommands = 0;

接下来,设置上述变量的属性

    /// <SUMMARY>
    /// The connection string to use
    /// </SUMMARY>
    public string ConnectionString
    {
        get
        {
            return(connstring);
        }
        set 
        {
            this.connstring = value;
        }
    }


    /// <SUMMARY>
    /// The message show to user in form
    /// </SUMMARY>
    public string WaitMessage
    {
        get
        {
            return(waitmessage);
        }
        set
        {
            // WaitMessage represents a label type object
            WaitMessage.Text = value;
        }
    }

好的,在这个阶段,我们编写了两个属性来处理内部变量,以便在未来的方法中使用。 随着查询的字符串数组的增长,我们必须调整它的大小。 让我们首先添加私有函数来处理数组增长

    /// <summary>
    /// Add an query to the queries collection
    /// </summary>
    /// <param name="sQuery">the query to add</param>
    private Array ResizeArray(Array QueryArray, int NewSize) 
    {
        // Check to see the type of the elements
        Type QueryArrayType = QueryArray.GetType().GetElementType();
        // Build our new array maintaining the original type
        Array NewQueryArray = Array.CreateInstance(QueryArrayType, NewSize);
        // Copy the values set to the new array
        Array.Copy(QueryArray, 0, NewQueryArray, 0, 
                   Math.Min(QueryArray.Length, NewSize));
                
        return NewQueryArray;
    }

那么,这个函数是如何工作的。 首先,我们获取数组中元素的类型,声明一个 Type 类型的新对象,并从原始数组构建一个新数组。 接下来,将我们现有的数据从原始数组复制到我们全新的数组中,最后返回它。 通过这个函数,我们可以根据需要添加尽可能多的查询,这个函数会根据需要调整我们数组的大小。

接下来,我们将编写 LockTablesReleaseTables 函数,但首先,简单解释一下我们将要使用的 MySQL 函数。

自从 MySQL 版本 3.21.27 发布以来,数据库引擎允许用户级别的锁定。 如果您的系统上安装了 MySQL,您可以试用 GET_LOCKRELEASE_LOCK 函数。 最近,MySQL 开发人员添加了 IS_FREE_LOCK 函数来检查锁的状态。 此功能仅从 4.0.2 版本开始提供。

现在,回到代码。 LockTable 是处理锁定并向用户反馈的函数,它会持续循环直到获得锁定。 我没有添加超时控制变量,因为我不需要它。 最后,ReleaseTable 函数将处理数据库用户级别锁的释放。 我使用 try / catch 块编写了 LockTableReleaseTable 函数,以便安全地处理数据库异常。 如果一切顺利,这些函数将返回 true;如果发生异常,则返回 false。

最后,是核心公共函数:AddQueryExecuteQueries。 函数 AddQuery 只是将查询添加到我们的 QueryCollection 字符串数组中。 它使用上面描述的 ResizeArray 函数来根据需要扩展字符串数组 QueryCollectionExecuteQueries 是我们的主要函数,它将执行所有操作。 它调用 LockTable 函数来锁定用户级别的表,初始化一个 Transaction 对象,将查询放入数据库,提交或回滚事务,最后调用 ReleaseTable 函数并返回执行操作的结果,如果运行良好则为 true,如果发生异常则为 false。

private bool LockTables()
    {
        // Build the connection object
        OdbcConnection OdbcMyConnection = new OdbcConnection(connstring);
        OdbcMyConnection.Open();
        // Our var to see how things end up
        bool bStatus = false;

        // Build the command object
        OdbcCommand OdbcMyCommand = OdbcMyConnection.CreateCommand();
        
        // In MySQL the function IS_FREE_LOCK is called by:
        // IS_FREE_LOCK(name_of_lock)
        OdbcMyCommand.CommandText = "SELECT IS_FREE_LOCK('OdbcExecuter')";
        int nStatus = 0;
        while (!bStatus)
        {
            // Execute function IS_FREE_LOCK and see what returns
            bStatus = Convert.ToBoolean(OdbcMyCommand.ExecuteScalar());
            if (bStatus) break;  // Could lock the table, let's exit the cycle

            // Still trying to lock, let's give feedback to user
            ldots.Text += ".";                
            Thread.Sleep(400);
            Application.DoEvents();                
        }

        // The lock is free for us, let's lock
        try
        {
            // Execute lock query
            // In MySQL the function GET_LOCK is called by:
            // GET_LOCK(name_of_lock, timeout seconds)
            OdbcMyCommand.CommandText = "SELECT GET_LOCK('OdbcExecuter',60)";
            nStatus = Convert.ToInt32(OdbcMyCommand.ExecuteScalar());
            if (nStatus == 1) bStatus = true;
            else bStatus = false;
        }
        catch (OdbcException e)
        {
            // Something bad happened, let the user know
            MessageBox.Show(this, e.ToString());
            bStatus = false;
        }

        // Close the connection object and return the result
        OdbcMyCommand.Dispose();
        OdbcMyConnection.Close();
        return bStatus;
    }

    private bool ReleaseTables()
    {
        // Build the connection object
        OdbcConnection OdbcMyConnection = new OdbcConnection(connstring);
        OdbcMyConnection.Open();
        // Our var to see how things end up
        bool bStatus = false;

        // Build our command object
        OdbcCommand OdbcMyCommand = OdbcMyConnection.CreateCommand();
        
        // See if our tables are already loocked
        try
        {
            // Execute the release lock query
            int nStatus = 0;
            // In MySQL the function RELEASE_LOCK is called by:
            // RELEASE_LOCK(name_of_lock)
            OdbcMyCommand.CommandText = "SELECT RELEASE_LOCK('OdbcExecuter')";
            nStatus = Convert.ToInt32(OdbcMyCommand.ExecuteScalar());
            if (nStatus == 1) bStatus = true;
            else bStatus = false;
        }
        catch (OdbcException e)
        {
            // Something bad happened, let the user know
            MessageBox.Show(this, e.ToString());
            bStatus = false;
        }

        // Close the connection object and return the result
        OdbcMyCommand.Dispose();
        OdbcMyConnection.Close();            
        return bStatus;
    }

公共函数

    /// <summary>
    /// Add an query to the queries collection
    /// </summary>
    /// <param name="sQuery">the query to add</param>
    public void AddQuery(string sQuery)
    {            
        // Check to see if our string array as elements
        if (nCommands > 0)
            // Resize the array and cast to prevent an exception throw
            QueryCollection = (string[])ResizeArray(QueryCollection, 
                                           QueryCollection.Length + 1);

        // Store the new query passed
        QueryCollection[nCommands] = sQuery;
        nCommands++;
    }

    /// <summary>
    /// Executes the stored queries in the query collection
    /// </summary>
    /// <returns>operation result</returns>
    public bool ExecuteQueries()
    {
        // Our var to see how things end up
        bool bStatus = false;

        // Force the form to show to the user
        if (!this.Focus())
        {
            this.TopMost = true;            // force window to show on top
            this.ShowInTaskbar = false;     // hide window from taskbar
            this.Show();                    // show window
        }

        // Build the connection object
        OdbcConnection OdbcMyConnection = new OdbcConnection(connstring);
        OdbcMyConnection.Open();

        // Start our transaction
        OdbcCommand OdbcMyCommand = OdbcMyConnection.CreateCommand();
        OdbcTransaction transact = 
          OdbcMyConnection.BeginTransaction(IsolationLevel.ReadCommitted);
        OdbcMyCommand.Transaction = transact;

        if (LockTables())
        {
            try
            {
                // Execute the queries in our QueryCollection array
                for (int nQuerys = 0; nQuerys < nCommands; nQuerys++)
                {
                    OdbcMyCommand.CommandText = QueryCollection[nQuerys];
                    OdbcMyCommand.ExecuteNonQuery();
                }

                // Commit our queries to the database                            
                transact.Commit();
                bStatus = true;
            }
            catch (Exception cmex)
            {
                try
                {
                    // Something bad happened, let's roll back our transaction
                    transact.Rollback();
                }
                catch (OdbcException ex)
                {
                    // Something bad happened, let the user know
                    MessageBox.Show(this, ex.ToString());
                }
                // Let the user know what happened with the transaction
                MessageBox.Show(this, cmex.ToString());
                bStatus = false;
            }
            finally
            {
                // Finally, let's end up our objects
                OdbcMyCommand.Dispose();
                OdbcMyConnection.Close();
            }
        }
        // We finish executing the queries, let's release the tables
        ReleaseTables();
        this.Hide();
        return bStatus;
    }
    
    public void CleanQueries()
    {
        QueryCollection.Initialize();
        QueryCollection = new string[1];
        nCommands = 0;
    }

好的,这结束了我们对 OdbcExecuter 类的编码。 如果您想将它包含在您的项目中,请随意下载该类并进行实现。

© . All rights reserved.