为什么这个查询会产生文件共享冲突?

本文关键字:文件共享 冲突 查询 为什么 | 更新日期: 2023-09-27 18:07:26

下面的代码给了我这个错误(我从catch块中的MessageBox.Show()中得到它)

" PopulateBla()中的异常:存在文件共享违规。一个不同的进程可能正在使用文件[,,,,,,]

using (SqlCeCommand cmd = new SqlCeCommand(SQL_GET_VENDOR_ITEMS, new SqlCeConnection(SQLCE_CONN_STR))) 
{
    cmd.Parameters.Add("@VendorID", SqlDbType.NVarChar, 10).Value = vendorId; 
    cmd.Parameters.Add("@VendorItemID", SqlDbType.NVarChar, 19).Value = vendorItemId;
    try 
    {
        cmd.Connection.Open();
        using (SqlCeDataReader SQLCEReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) 
        {
            if (SQLCEReader.Read())  
            {
                itemID = SQLCEReader.GetString(ITEMID_INDEX);
                packSize = SQLCEReader.GetString(PACKSIZE_INDEX);
                recordFound = true;
            }
        }
    } 
    catch (SqlCeException err) 
    {
        MessageBox.Show(string.Format("Exception in PopulateControlsIfVendorItemsFound: {0}'r'n", err.Message));//TODO: Remove
    } 
    finally 
    {
        if (cmd.Connection.State == ConnectionState.Open) 
        {
            cmd.Connection.Close();
        }
    }
}

SQL_GET_VENDOR_ITEMS是我的查询字符串。

这里可能发生什么文件共享问题?

更新

这种代码使得下面的攻击所推荐的重构变得困难:

public void setINVQueryItemGroup( string ID )
{
    try
    {
        dynSQL += " INNER JOIN td_item_group ON t_inv.id = td_item_group.id AND t_inv.pack_size = td_item_group.pack_size WHERE td_item_group.item_group_id = '" + ID + "'";
    } 
    catch( Exception ex )
    {
        CCR.ExceptionHandler( ex, "InvFile.setINVQueryDept" );
    }
}

一个SQL语句被附加到一个单独的方法,改变一个全局变量(dynSQL),同时可能允许SQL注入(取决于在哪里/如何分配ID)。如果这还不够,抛出的任何异常都可能误导疲惫的猎人,因为它表明它发生在不同的方法中(无疑是粗心的复制-粘贴操作的受害者)。

这是"编码恐怖"的价值。在短短的几行代码中,您可以忽略多少最佳实践?

下面是另一个例子:

string dynSQL = "SELECT * FROM purgatory WHERE vendor_item = '" + VendorItem + "' ";
if (vendor_id != "")
{
    dynSQL += "AND vendor_id = '" + vendor_id + "' ";
}

可以通过将参数替换为"? ",但是决定要分配哪些/多少个参数的代码将比Joe Garagiola的平均代码丑42倍。

为什么这个查询会产生文件共享冲突?

我非常喜欢Chris使用单一连接到数据库的想法。你可以像这样将它声明为你的类的全局变量:

public ClayShannonDatabaseClass
{
    private SqlCeConnection m_openConnection;
    public ClayShannonDatabaseClass()
    {
       m_openConnection = new SqlCeConnection();
       m_openConnection.Open();
    }
    public void Dispose()
    {
       m_openConnection.Close();
       m_openConnection.Dispose();
       m_openConnection = null;
    }
}

当你试图打开数据库时,我猜你的代码会崩溃。

为了验证这一点,您可以在代码中插入一个整数值来帮助您调试。

的例子:

int debugStep = 0;
try 
{
    //cmd.Connection.Open(); (don't call this if you use m_openConnection)
    debugStep = 1;
    using (SqlCeDataReader SQLCEReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) 
    {
        debugStep = 2;
        if (SQLCEReader.Read())  
        {
            debugStep = 3;
            itemID = SQLCEReader.GetString(ITEMID_INDEX);
            debugStep = 4;
            packSize = SQLCEReader.GetString(PACKSIZE_INDEX);
            debugStep = 5;
            recordFound = true;
        }
    }
} 
catch (SqlCeException err) 
{
    string msg = string.Format("Exception in PopulateControlsIfVendorItemsFound: {0}'r'n", err.Message);
    string ttl = string.Format("Debug Step: {0}", debugStep);
    MessageBox.Show(msg, ttl); //TODO: Remove
}
// finally (don't call this if you use m_openConnection)
// {
//     if (cmd.Connection.State == ConnectionState.Open) 
//     {
//         cmd.Connection.Close();
//     }
// }

我猜你的错误在第一步

如果文件没有被标记为只读(您检查了这一点,对吗?),那么您就有另一个对该文件具有非共享锁的进程。

SQL CE附带的isql.exe数据库浏览器如果在后台运行是一个常见的罪魁祸首。

根据你的SQLCE版本,很有可能另一个进程有一个打开的连接(不记得哪个版本开始允许多个进程连接),所以如果你在后台有任何其他应用程序打开了它,这可能也是一个问题。

你还使用了一船到那个数据库的连接,它们并不总是被清理并立即释放Dispose。我强烈建议构建一个简单的连接管理器类,它保持一个(或更像两个)到数据库的连接,并且只在所有操作中重用它们。