立即执行 SELECT,然后通过 .NET 在 Access 中执行 UPDATE
Posted
技术标签:
【中文标题】立即执行 SELECT,然后通过 .NET 在 Access 中执行 UPDATE【英文标题】:Performing a SELECT immediately followed by an UPDATE in Access via .NET 【发布时间】:2015-10-01 14:59:42 【问题描述】:我的问题比较简单,但我还没有找到答案。我有一个只包含一行的表。这一行有两列,ClientCode 和 ClientIndex。
我有一个如下所示的选择查询:
SELECT i.ClientCode + FORMAT(i.ClientIndex, "000000") FROM Indexes as I;
现在,在我运行 select 之后,我想将 ClientIndex 加一。
UPDATE Indexes SET ClientIndex = ClientIndex + 1;
动机:我希望能够创建连续的报告编号。因此,每次生成报告时,我都希望 ClientIndex 增加。为此,我需要锁定表格,选择我的号码,增加索引并解锁表格。
这在 MS Access 2013 中是否可行?使用存储过程在 Sql 中是微不足道的;但是要求状态访问并且没有办法绕过这个要求。此外,我正在构建一个客户端应用程序(使用 .NET 和 F#),它将检索报告编号。
编辑:似乎人们并没有真正理解这个问题。我希望SELECT
和UPDATE
这两个语句在同一个执行中运行。我确实不想从某个客户端调用选择和更新。
普通旧 t-sql 中的 SP 看起来像:
CREATE PROCEDURE something
AS
BEGIN
declare @result as nchar(10);
set @result = <<select query>>;
<<update query>>;
select @result;
END
编辑:我正在构建一个 .NET F# 应用程序,它将调用 Access 数据库并检索报告编号。此应用程序将在 Windows 服务器上的 Windows 服务中运行。这个报告编号可以在很长的时间间隔内同时调用大约 100 次。
【问题讨论】:
您的更新声明有什么问题? (除非它没有 where 条件) 你为什么不直接试试?这将比写问题花费更少的时间...... 感谢您的回复。我希望它们像“在同一条语句中”一样“在彼此之后”运行我不希望调用代码必须对数据库进行两次调用才能使其正常工作。换句话说,我希望SELECT
语句和UPDATE
语句在同一个执行中运行。
编辑了我的问题,如果仍然不清楚,请告诉我,我可以尝试更好地解释它。但我们的想法是在单个报表中为每个报告生成一个唯一的“业务编号”。 (所以,是的,连接字符串,第一份报告得到 2015-RPT-000001 和第二份报告 2015-RPT-000002 之类的东西。我已经愚蠢地完成了数字的创建,因为这并不重要。重要的是单次执行返回一个值并更新数据库。
@HansUp 如果可以从 .NET 代码调用此 VBA 过程,并且如果对 VBA 脚本的 2 个并发调用执行串行,这样就不会出现合适的双数。 (当然,我希望以更“sql-y”的方式来做)-谢谢你的思考,我很感激。
【参考方案1】:
我不希望调用代码必须对数据库进行两次调用才能使其正常工作。换句话说,我希望 SELECT 语句和 UPDATE 语句在同一个执行中运行。
Access数据库引擎不支持多语句批处理,所以无法执行...
SELECT i.ClientCode + FORMAT(i.ClientIndex, "000000") FROM Indexes as I;
UPDATE Indexes SET ClientIndex = ClientIndex + 1;
... 一口气。每个 SQL 语句都必须单独执行。
现在,如果这两个语句在隔离级别为“可序列化”的事务中执行,那将不是问题。不幸的是,Access ODBC 驱动程序和 Access OLEDB 提供程序都不支持 System.Data.IsolationLevel.Serializable
进行事务处理。他们支持的最高隔离级别是ReadCommitted
,这还不够严格,无法防止两个进程获得相同的ClientIndex。
据我所知,模拟可序列化事务的唯一方法是使用带有悲观锁定的 Access DAO,如下所示:
// COM Reference required:
// Microsoft Office 14.0 Access Database Engine Object Library
//
var dbe = new DBEngine();
Database db = dbe.OpenDatabase(@"\\DINSDALE\Public\test\locktestBE.accdb");
Recordset rst = db.OpenRecordset("SELECT ClientIndex FROM Indexes",
RecordsetTypeEnum.dbOpenDynaset,
RecordsetOptionEnum.dbFailOnError,
LockTypeEnum.dbPessimistic);
bool keepTrying = true;
while (keepTrying)
try
rst.Edit();
int nextId = rst.Fields["ClientIndex"].Value; // get next ID,
rst.Fields["ClientIndex"].Value = nextId + 1; // increment value, and
rst.Update(); // write it back
rst.Close();
Console.WriteLine("The assigned ID is 0", nextId);
keepTrying = false;
catch (System.Runtime.InteropServices.COMException e)
if (!e.Message.StartsWith("Could not update; currently locked by user"))
throw;
db.Close();
但是,在继续使用 Access 数据库作为服务的数据存储之前,您确实应该仔细考虑。处理高并发和执行粒度锁定并不是 Access 数据库引擎的强项。 (Microsoft“强烈建议不要在 Web 应用程序中使用 Access”有几个原因 - 参考:here - 听起来其中许多原因也适用于您的应用程序。)
【讨论】:
感谢您的出色回答。我完全理解 Access 不擅长并发,现在我知道不支持批处理语句。我希望我有其他数据库选项,但我坚持使用这个。我认为上面的代码是唯一的选择,我想我必须为了实用性而牺牲并行性。 是否有另一种方法可以在不需要批处理语句的情况下从 Access 数据库生成唯一的、连续的“报告编号”?我会提出另一个问题,但它是原始问题的一部分,所以如果这个“跟进”在任何方面都不合适,请告诉我。以上是关于立即执行 SELECT,然后通过 .NET 在 Access 中执行 UPDATE的主要内容,如果未能解决你的问题,请参考以下文章