仅在 SELECT returns 时执行 DELETE
Execute DELETE only when the SELECT returns
我有一个用其他数据库数据更新本地数据库的例程。
我只执行 DELETE 然后 INSERT INTO tblX (SELECT * FROM tblY (tblY 是链接 table )),如下
问题是,在某些情况下,SELECT 在 DELETE 之后需要很长时间,我会希望减少用户在处理过程中向 table 提出请求的可能性。
我想知道是否有某种机制可以仅在 SELECT 的 return 之后执行 DELETE .
conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal());
conn.Open();
OleDbCommand cmd = new OleDbCommand(" DELETE * FROM tblClienteContato; ", conn);
cmd.ExecuteNonQuery();
cmd = new OleDbCommand(" INSERT INTO tblClienteContato " +
" SELECT * FROM tblClienteContatoVinculada;", conn);
cmd.ExecuteNonQuery();
听起来您需要做的是将这两个命令包装在一个事务中。
交易的妙处在于,它要么 ALL WORKS 要么 ALL FAILS,这意味着如果发生某些事情会停止 select语句,数据库不会最终确定删除语句。
这看起来是一个很好的例子:
https://msdn.microsoft.com/en-us/library/93ehy0z8(v=vs.110).aspx
注意他们只有一个命令对象,并替换CommandText,而不是每次都创建一个新对象。这可能很重要。
尝试这样的事情:
conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal());
OleDbCommand cmd = new OleDbCommand();
OleDbTransaction transaction = null;
try {
conn.Open();
transaction = conn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Connection = conn;
cmd.Transaction = transaction;
cmd.CommandText = " DELETE * FROM tblClienteContato; ";
cmd.ExecuteNonQuery();
cmd.CommandText = " INSERT INTO tblClienteContato " +
" SELECT * FROM tblClienteContatoVinculada;";
cmd.ExecuteNonQuery();
// The data isn't _finally_ completed until this happens
transaction.Commit();
}
catch (Exception ex)
{
// Something has gone wrong.
// do whatever error messaging you do
Console.WriteLine(ex.Message);
try
{
// Attempt to roll back the transaction.
// this means your records won't be deleted
transaction.Rollback();
}
catch
{
// Do nothing here; transaction is not active.
}
}
您应该查看 BeginTransaction、Commit 和回滚,这是一个示例:
_con.Open();
_con_trans = _con.BeginTransaction();
using(SqlCommand cmd = _con.CreateCommand())
{
cmd.CommandText = "delete from XXXXX";
cmd.CommandType = CommandType.Text;
cmd.Transaction = _con_trans;
cmd.ExecuteNonquery();
}
using(SqlCommand cmd = _con.CreateCommand())
{
cmd.CommandText = "insert into XXXX";
cmd.CommandType = CommandType.Text;
cmd.Transaction = _con_trans;
cmd.ExecuteNonquery();
}
_con_trans.Commit();
_con_trans = null;
_con.Close();
这样,所有内容都封装在单个事务中,因此当删除开始时,table 将被锁定以进行读写。
在不了解 table 的架构的情况下,很难确定删除过程花费大量时间的原因。
将命令包装在事务中的另一种方法是使用 DROP TABLE
命令简单地删除 table 本身而不是其中的数据。然后您可以使用 SELECT...INTO...FROM
语句重新创建 table。这样做的一个潜在优势是模式将完全匹配,并且不需要进行任何固有的转换(例如 decimal 到 int)。
using (conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal())) {
conn.Open();
using (OleDbCommand cmd = new OleDbCommand()) {
cmd.CommandText = "DROP TABLE tblClienteContato; ";
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT * INTO tblClienteContato FROM tblClienteContatoVinculada;";
cmd.ExecuteNonQuery();
}
}
以下不适用于此处 (MS Access),但可能适用于其他 SQL 变体
另一种选择是使用 TRUNCATE
命令,这将一次性删除 table 中的所有内容。没有单独的行的日志记录,并且索引(如果存在)不需要在被删除的每一行上重新计算。此方法的问题在于,这在事务中不起作用。如果有标识列,该值也将被重置。这还有其他潜在的缺点,但不知道 table 的设计,我无法识别它们。
using (conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal())) {
conn.Open();
using (OleDbCommand cmd = new OleDbCommand()) {
cmd.CommandText = "TRUNCATE TABLE tblClienteContato; ";
cmd.ExecuteNonQuery();
cmd.CommandText = " INSERT INTO tblClienteContato " +
" SELECT * FROM tblClienteContatoVinculada;";
cmd.ExecuteNonQuery();
}
}
正如 Greg 评论的那样,我创建了临时表以从外部数据库接收数据,然后将数据传输到最终表,因此用户受到影响的可能性非常低。
我有一个用其他数据库数据更新本地数据库的例程。
我只执行 DELETE 然后 INSERT INTO tblX (SELECT * FROM tblY (tblY 是链接 table )),如下
问题是,在某些情况下,SELECT 在 DELETE 之后需要很长时间,我会希望减少用户在处理过程中向 table 提出请求的可能性。
我想知道是否有某种机制可以仅在 SELECT 的 return 之后执行 DELETE .
conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal());
conn.Open();
OleDbCommand cmd = new OleDbCommand(" DELETE * FROM tblClienteContato; ", conn);
cmd.ExecuteNonQuery();
cmd = new OleDbCommand(" INSERT INTO tblClienteContato " +
" SELECT * FROM tblClienteContatoVinculada;", conn);
cmd.ExecuteNonQuery();
听起来您需要做的是将这两个命令包装在一个事务中。
交易的妙处在于,它要么 ALL WORKS 要么 ALL FAILS,这意味着如果发生某些事情会停止 select语句,数据库不会最终确定删除语句。
这看起来是一个很好的例子: https://msdn.microsoft.com/en-us/library/93ehy0z8(v=vs.110).aspx
注意他们只有一个命令对象,并替换CommandText,而不是每次都创建一个新对象。这可能很重要。
尝试这样的事情:
conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal());
OleDbCommand cmd = new OleDbCommand();
OleDbTransaction transaction = null;
try {
conn.Open();
transaction = conn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Connection = conn;
cmd.Transaction = transaction;
cmd.CommandText = " DELETE * FROM tblClienteContato; ";
cmd.ExecuteNonQuery();
cmd.CommandText = " INSERT INTO tblClienteContato " +
" SELECT * FROM tblClienteContatoVinculada;";
cmd.ExecuteNonQuery();
// The data isn't _finally_ completed until this happens
transaction.Commit();
}
catch (Exception ex)
{
// Something has gone wrong.
// do whatever error messaging you do
Console.WriteLine(ex.Message);
try
{
// Attempt to roll back the transaction.
// this means your records won't be deleted
transaction.Rollback();
}
catch
{
// Do nothing here; transaction is not active.
}
}
您应该查看 BeginTransaction、Commit 和回滚,这是一个示例:
_con.Open();
_con_trans = _con.BeginTransaction();
using(SqlCommand cmd = _con.CreateCommand())
{
cmd.CommandText = "delete from XXXXX";
cmd.CommandType = CommandType.Text;
cmd.Transaction = _con_trans;
cmd.ExecuteNonquery();
}
using(SqlCommand cmd = _con.CreateCommand())
{
cmd.CommandText = "insert into XXXX";
cmd.CommandType = CommandType.Text;
cmd.Transaction = _con_trans;
cmd.ExecuteNonquery();
}
_con_trans.Commit();
_con_trans = null;
_con.Close();
这样,所有内容都封装在单个事务中,因此当删除开始时,table 将被锁定以进行读写。
在不了解 table 的架构的情况下,很难确定删除过程花费大量时间的原因。
将命令包装在事务中的另一种方法是使用 DROP TABLE
命令简单地删除 table 本身而不是其中的数据。然后您可以使用 SELECT...INTO...FROM
语句重新创建 table。这样做的一个潜在优势是模式将完全匹配,并且不需要进行任何固有的转换(例如 decimal 到 int)。
using (conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal())) {
conn.Open();
using (OleDbCommand cmd = new OleDbCommand()) {
cmd.CommandText = "DROP TABLE tblClienteContato; ";
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT * INTO tblClienteContato FROM tblClienteContatoVinculada;";
cmd.ExecuteNonQuery();
}
}
以下不适用于此处 (MS Access),但可能适用于其他 SQL 变体
另一种选择是使用 TRUNCATE
命令,这将一次性删除 table 中的所有内容。没有单独的行的日志记录,并且索引(如果存在)不需要在被删除的每一行上重新计算。此方法的问题在于,这在事务中不起作用。如果有标识列,该值也将被重置。这还有其他潜在的缺点,但不知道 table 的设计,我无法识别它们。
using (conn = new OleDbConnection(Conexao.getConexaoPainelGerencialLocal())) {
conn.Open();
using (OleDbCommand cmd = new OleDbCommand()) {
cmd.CommandText = "TRUNCATE TABLE tblClienteContato; ";
cmd.ExecuteNonQuery();
cmd.CommandText = " INSERT INTO tblClienteContato " +
" SELECT * FROM tblClienteContatoVinculada;";
cmd.ExecuteNonQuery();
}
}
正如 Greg 评论的那样,我创建了临时表以从外部数据库接收数据,然后将数据传输到最终表,因此用户受到影响的可能性非常低。