实际上我想在一个表上应用锁,这样其他进程就不能执行 DML(插入/更新/删除但可以执行选择)或在“进程执行”时锁定该表。
LOCK TABLE table-name IN EXCLUSIVE MODE
我应该如何用 C# 编写它?
// ..... 进程执行 ....
如何解除锁定?我猜要么提交要么回滚。
有什么建议么?
锁将在提交或回滚时重新释放
OracleConnection conn= new OracleConnection("Data Source=datasrc;User=USER;Password=passwd");
conn.Open();
OracleTransaction tr = conn.BeginTransaction();
OracleCommand cmd = new OracleCommand("LOCK TABLE TABLE_NAME IN EXCLUSIVE MODE",conn,tr);
cmd.ExecuteNonQuery();
Console.ReadLine();
tr.Commit();
conn.Close();
为什么需要锁表?使用事务范围对象指定隔离级别就足够了吗?例如
TransactionOptions TransOpt = New TransactionOptions();
TransOpt.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TransOptions))
{
...
}
请检查您的要求。
通过利用另一种策略可以解决此问题。既不通过以下方式解决它:
EXCLUSIVE LOCKING(因为我意识到如果在我的进程正在进行时有另一个事务更新了我的表,那么由于锁定而无法更新表,但是一旦我的进程完成,意味着锁现在被释放,如果另一个事务仍然处于暂停状态,那么另一笔交易将立即更新我的表格。这对我来说不会有成果。)也不能通过以下方式解决:
IsolationLevel.Serializable(因为分布式事务不支持可序列化的事务隔离级别。)
因此,在我的表中的每个条目上,我都会确定是否有任何事务(无论是分布式的还是本地的)阻塞了我的表。如果有,我会识别该会话并强行终止该会话。这完全适合我的场景:
Database db = DataRepository.GetDatabase();
int result, session_id = 0;
string kill_session, serial = null;
string chk_lock = "SELECT l.session_id,v.serial# ,"
+"object_name FROM dba_objects o, gv$locked_object l, "
+"v$session v WHERE o.object_id = l.object_id and "
+"l.SESSION_ID=v.sid";
DbDataReader rdr_blkAccount;
try{
//MY PROCESS RUNS HERE...
}
catch(Exception excep)
{
//...
}
finally
{
rdr_blkAccount = db.ExecuteReader(chk_lock);
while (rdr_blkAccount.Read())
{
if (rdr_blkAccount[2].ToString().ToUpper() == "ACCOUNT")
{
session_id = Convert.ToInt32(rdr_blkAccount[0]);
serial = session_id.ToString() + ','
+ Convert.ToInt32(rdr_blkAccount[1]).ToString();
kill_session = "alter system kill session '" + serial + "'";
result = db.ExecuteNonQuery(kill_session);
logger.Log( LogLevel.Warning
, string.Format("Session_id '{0}' has been forcefully killed"
, serial));
}
}
rdr_blkAccount.Close();
}