3

在您需要提交之前或在 Access/Jet 引发错误之前,您可以在 Access 事务中执行的插入数量是否有限制?

我目前正在运行以下代码,希望确定这个最大值是多少。

OleDbConnection cn =
                new OleDbConnection(
                    @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\temp\myAccessFile.accdb;Persist Security Info=False;");
            try
            {
                cn.Open();
                oleCommand = new OleDbCommand("BEGIN TRANSACTION", cn);               
                oleCommand.ExecuteNonQuery();    
                oleCommand.CommandText =
                            "insert into [table1] (name) values ('1000000000001000000000000010000000000000')";

                for (i = 0; i < 25000000; i++)
                {
                    oleCommand.ExecuteNonQuery();
                }                

                oleCommand.CommandText = "COMMIT";
                oleCommand.ExecuteNonQuery();
            }
            catch (Exception ex)
            {

            }
            finally
            {
                try
                {

                    oleCommand.CommandText = "COMMIT";
                    oleCommand.ExecuteNonQuery();                    
                }

                catch{}

                if (cn.State != ConnectionState.Closed)
                {
                    cn.Close();
                }
            }

当我在单个未提交事务中达到 2,333,920 次插入时,我在生产应用程序上收到的错误是:“超出文件共享锁计数。增加 MaxLocksPerFile 注册表项”。禁用事务解决了这个问题。

4

2 回答 2

4

我刚刚在 .accdb 数据库中的表上成功创建并提交了 5,000,000 次插入的事务。一个显着的区别是我没有直接发出BEGIN TRANSACTIONCOMMIT声明,而是使用了一个OleDbTransaction对象:

cmd.CommandText =
    @"INSERT INTO Companies (ID, CompanyName) VALUES (?, ?)";
cmd.Parameters.Add("?", OleDbType.Integer);
cmd.Parameters.Add("?", OleDbType.VarWChar, 255);
cmd.Prepare();

OleDbTransaction tran =  con.BeginTransaction();
cmd.Transaction = tran;
for (int i = 1; i <= 5000000; i++)
{
    if ((i % 100) == 0)
    {
        Console.WriteLine(i.ToString());
    }
    cmd.Parameters[0].Value = i;
    cmd.Parameters[1].Value = "Company" + i.ToString();
    cmd.ExecuteNonQuery();
}
tran.Commit();

编辑回复:评论

在成功创建并提交了 10,000,000 次插入事务,并验证 a.Rollback()确实有效(好建议,neoistheone!)后,我检查IsolationLevel了事务的。ACE.OLEDB 驱动程序的默认值IsolationLevel显然是ReadCommitted,根据MSDN意味着:

在读取数据的同时持有共享锁以避免脏读,但在事务结束之前可以更改数据,导致不可重复读取或幻像数据。

维基百科对这些不同的“阅读现象”有很好的描述

也许如果我要指定更严格的隔离级别(Serializable如直到他们承诺。

重新编辑:性能

由于在事务中包装大量 INSERT 操作的一个相当常见的原因是为了更快地完成它们,因此我测试了一批 100,000 个插入和不带OleDbTransaction. (在这两种情况下都使用了准备好的语句。)没有OleDbTransaction批处理需要大约 36 秒才能完成。OleDbTransaction使用默认隔离级别 ( )启用将ReadCommitted经过的时间减少到大约 23 秒。

于 2013-11-01T13:52:47.700 回答
3

是的,实际上是有限制的。你已经清楚地达到了它。根据微软的文档

如果执行事务所需的锁数超过每个文件的最大锁数,则会发生错误。

在那个链接有几个解决方法。第二个更现实,它暂时改变了最大锁。

于 2013-11-01T12:50:00.643 回答