【问题标题】:Execute DELETE only when the SELECT returns仅当 SELECT 返回时执行 DELETE
【发布时间】:2017-09-21 18:19:52
【问题描述】:

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

我只执行了一个DELETE,然后是一个INSERT INTO tblX(SELECT * FROM tblY(tblY 是链接表)),如下。

问题是,在某些情况下 SELECTDELETE 之后需要很长时间,我想减少用户提出请求的可能性到这个表,而它的处理。

我想知道是否有某种机制仅在 SELECT 返回后执行 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();

【问题讨论】:

    标签: c# sql ms-access oledb


    【解决方案1】:

    听起来您需要做的是将这两个命令包装在一个事务中。

    事务很酷的一点是它要么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.
        }
    }
    

    【讨论】:

    • Greg,我在执行“BeginTransaction”时收到以下消息:“不支持隔离级别和加强隔离级别”
    • 不带参数试试? Access & Jet 可能不支持隔离级别。
    • 另一种选择是使用临时表分两个阶段执行此操作。从临时表中删除(没有人使用过),将慢速插入到临时表中。完成后,从主表中删除,然后在主表中执行插入操作,但从本地临时表(应该很快)而不是远程临时表中选择。这意味着主表忙碌的时间应该短得多。
    • 伟大的格雷格。这正是我所做的。所有事务命令都返回消息“既不支持隔离级别也不支持加强”,因此我创建了临时表。把它作为答案....
    【解决方案2】:

    您应该查看 BeginTransaction、Commit 和 rollback,这是一个示例:

        _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();
    

    这样,所有的东西都包裹在一个事务中,所以当删除开始时,表将被锁定以进行读写。

    【讨论】:

    • Alex,我在执行“BeginTransaction”时收到以下消息:“不支持隔离级别和加强隔离级别”
    【解决方案3】:

    在不知道表的架构的情况下,很难确定删除过程为何会花费大量时间。

    在事务中包装命令的另一种方法是使用DROP TABLE 命令简单地删除表本身而不是其中的数据。然后您可以使用SELECT...INTO...FROM 语句重新创建表来重新创建。这样做的一个潜在优势是模式将完全匹配,并且不需要进行任何固有的转换(例如十进制到整数)。

        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 命令,该命令将一举删除表中的所有内容。没有记录各个行,并且不需要在删除的每一行上重新计算索引(如果存在)。这个方法的问题是这在事务中不起作用。如果有一个标识列,该值也将被重置。这还有其他潜在的缺点,但在不知道桌子的设计的情况下,我无法识别它们。

    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();
        }
    }
    

    【讨论】:

    • 疯了,我仍然遇到选择命令延迟的问题。从表中删除数据后,需要很长时间才能在选择中获取新日期。
    • 如果在 MS Access 中运行会发生什么?
    【解决方案4】:

    正如 Greg 所说,我创建了临时表来接收来自外部数据库的数据,然后将数据传输到最终表,因此用户受到影响的概率非常低。

    【讨论】:

      猜你喜欢
      • 2011-11-26
      • 2013-03-25
      • 2017-04-10
      • 1970-01-01
      • 2012-11-20
      • 1970-01-01
      • 2012-11-02
      • 2021-07-21
      • 1970-01-01
      相关资源
      最近更新 更多