仅在 SELECT returns 时执行 DELETE

Execute DELETE only when the SELECT returns

我有一个用其他数据库数据更新本地数据库的例程。

我只执行 DELETE 然后 INSERT INTO tblX (SELECT * FROM tblY (tblY 是链接 table )),如下

问题是,在某些情况下,SELECTDELETE 之后需要很长时间,我会希望减少用户在处理过程中向 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 评论的那样,我创建了临时表以从外部数据库接收数据,然后将数据传输到最终表,因此用户受到影响的可能性非常低。