MySQL 的事务、锁定和表释放






3.20/5 (5投票s)
2004 年 4 月 17 日
3分钟阅读

101840

1717
实现一个简单的类来存储多个查询并针对 MySQL 数据库运行。
引言
在我的最后一个项目中,我需要开发一个类,该类可以简化针对我的 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
类型的新对象,并从原始数组构建一个新数组。 接下来,将我们现有的数据从原始数组复制到我们全新的数组中,最后返回它。 通过这个函数,我们可以根据需要添加尽可能多的查询,这个函数会根据需要调整我们数组的大小。
接下来,我们将编写 LockTables
和 ReleaseTables
函数,但首先,简单解释一下我们将要使用的 MySQL 函数。
自从 MySQL 版本 3.21.27 发布以来,数据库引擎允许用户级别的锁定。 如果您的系统上安装了 MySQL,您可以试用 GET_LOCK
和 RELEASE_LOCK
函数。 最近,MySQL 开发人员添加了 IS_FREE_LOCK
函数来检查锁的状态。 此功能仅从 4.0.2 版本开始提供。
现在,回到代码。 LockTable
是处理锁定并向用户反馈的函数,它会持续循环直到获得锁定。 我没有添加超时控制变量,因为我不需要它。 最后,ReleaseTable
函数将处理数据库用户级别锁的释放。 我使用 try
/ catch
块编写了 LockTable
和 ReleaseTable
函数,以便安全地处理数据库异常。 如果一切顺利,这些函数将返回 true;如果发生异常,则返回 false。
最后,是核心公共函数:AddQuery
和 ExecuteQueries
。 函数 AddQuery
只是将查询添加到我们的 QueryCollection
字符串数组中。 它使用上面描述的 ResizeArray
函数来根据需要扩展字符串数组 QueryCollection
。 ExecuteQueries
是我们的主要函数,它将执行所有操作。 它调用 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
类的编码。 如果您想将它包含在您的项目中,请随意下载该类并进行实现。