SQL触发器到应用程序[关闭]
Posted
技术标签:
【中文标题】SQL触发器到应用程序[关闭]【英文标题】:SQL Trigger to Application [closed] 【发布时间】:2021-04-26 20:00:10 【问题描述】:我有一个 SQL Server 数据库连接到组织运输的应用程序。就像日历时间表一样。有没有办法在一个用户进行更改时在应用程序中获取触发器(在我的情况下为更新),以便连接到数据库的所有其他应用程序更新到更新触发器调用?只是为了让所有应用程序更新到大多数原因数据。我正在使用 SQL 连接字符串。
Public Shared Sub Load(ByRef MyCollect As List(Of PAPaintSchedule), Filter As String, OrderBy As String)
MyCollect = New List(Of PAPaintSchedule)
Dim CMDValue As String = $"SELECT * FROM TableName"
If Filter IsNot Nothing Then CMDValue &= $" WHERE Filter"
If OrderBy IsNot Nothing Then CMDValue &= $" ORDER BY OrderBy"
CMDValue &= ";"
If SQLCon.State = System.Data.ConnectionState.Closed Then SQLCon.Open()
Dim CMD As New SqlCommand(CMDValue, SQLCon)
Dim reader As SqlDataReader = CMD.ExecuteReader()
Try
If reader.HasRows Then
While reader.Read()
Dim LF As New PAPaintSchedule With .Id = reader(0),
.PaintDate = reader(1),
.Total = reader(2),
.Notes = reader(5)
LF.HasChanges = False
MyCollect.Add(LF)
End While
End If
Catch ex As Exception
If Not SQLCon.State = System.Data.ConnectionState.Closed Then SQLCon.Close()
Finally
reader.Close()
CMD.Dispose()
If Not SQLCon.State = System.Data.ConnectionState.Closed Then SQLCon.Close()
End Try
If Not SQLCon.State = System.Data.ConnectionState.Closed Then SQLCon.Close()
End Sub
【问题讨论】:
有很多方法,但它是一个很大的话题,对于一个问题来说太大了。您需要研究选项,选择一个,试一试,然后在遇到困难时提出问题。 你当前的代码有很多问题:对SQL注入很危险,你也不应该缓存连接对象,你应该用Using
块来处理连接和阅读器
有许多策略,很大程度上取决于您希望如何管理它。您需要提出的问题,例如,如果用户在触发更新时正在编辑记录,会发生什么?这次更新的目的是什么?是否可以通过客户端定期轮询来管理?
每个应用都有自己的数据库吗?您是在寻求一种在数据库之间复制部分或全部数据的方法,还是在寻求一种让应用程序相互发送通知的方法,或者这是一个单一的数据库,但您只是希望客户端应用程序刷新?跨度>
同意,我的SQL注入是开放的,我需要重写加载函数。我写这个是为了提出这个问题。
【参考方案1】:
有一句格言有时会被误认为是笑话:计算机科学中只有两个困难:缓存一致性和命名事物。你的问题是关于前者的。
让客户及时了解最新数据的问题并不是真正的数据库问题。一些客户端库确实提供了一些机制,但通常问题与更新数据库无关。这是关于通知对等方,这是一个消息传递问题。 (例如,您可以通过自动发送电子邮件来处理问题。)对等点的数量越多,它们在世界各地的分布越广,时间和空间以及光速对仅仅定义“最近的”。
在数据库中,问题得到了更好的定义:您通常不希望出现最后写入获胜的情况。如果两个客户端读取相同的记录,一个更新它,然后另一个更新它,您不希望第二个更新成功,除非它包含第一个更新。而不是 read-write-write,您需要 read-write,read-write。
在 SQL 中,这通常通过隔离级别来解决。在最简单的情况下,作为事务的一部分,第一个读者可以阻止第二个读者直到他完成。问题是,什么是“完成”?午餐后?因为这通常是不可接受的,所以建议交互式应用程序的程序员永远不要在用户拥有控制权时保持事务打开。
在数据库革命初期开发的解决方法是乐观并发:允许多次读取,但每次写入都小心不要覆盖中间更新。这通常有效(因此是乐观的),因为通常用户不会竞争更新相同的记录。
一种实现不需要 DBMS 支持。读取发生在事务之外(无阻塞)。用户将修改后的数据输入到应用程序中。该应用程序还保留原始记录的副本。为了更新数据库,应用程序首先再次读取记录——这次是在一个事务中,阻塞其他记录——并将新读取的记录与原始记录进行比较。如果它们匹配,则应用更新的值,并关闭事务。
注意,这个 read-compare-update 过程不能简单地是一个 select 然后 update 使用 DBMS 的默认隔离级别.相反,它作为 UPDATE 语句的一部分在 DBMS 内部进行,该语句将更新限制为原始数据仍然存在于数据库中的“行”(通常只有 1 个)。 DBMS 报告有多少行受到影响,如果答案为零,则应用程序推断该行已同时更改。恢复依赖于应用程序,但一个明显的策略是向用户提供当前记录,然后重试。
为了促进乐观并发,许多 DBMS 提供了内置的并发控制数据类型,例如 SQL Server 中的 timestamp,它会在行更新时自动更改值。 “它改变了吗?”然后可以通过比较单个值而不是整行来回答问题。
如果这一切看起来毫无希望地笨拙或理论上,请考虑一下:这就是股市的运作方式。如果您发出以 Y 价格购买股票 X 的订单,其中 Y 是您屏幕上的当前价格(无论“当前”和“现在”是什么意思),没有人在等你,也没有人在等其他人.你甚至不共享一个系统。除非您支付巨额费用,否则您可能收到的任何价格更新都会被故意延迟。您的订单在所有其他订单的挤压中到达,并且与通常情况不同,许多其他订单很可能会竞争相同的 X @ Y。买卖订单在到达时按时间和价格排列。只有在最底层,远离人手的地方,事务才能确保每次更新都只使用“最新”数据。
【讨论】:
您提到应用程序保留了原始记录的副本,但 read-compare-update 发生在 DBMS 中。你能详细说明一下吗?应用程序会在调用 UPDATE 语句时提供它的记录副本吗? 感谢大家的意见!我昨天离开了一天。我正在使用多个应用程序连接到的单个数据库。应用程序连接以检索数据,然后在检索数据后释放连接。 @ÉtienneLaneville,基本上,是的,该语句使用存在量词:UPDATE table SET values WHERE EXISTS (SELECT 1 WHERE <a=old_a and b=old_b etc>)
。这会导致 DBMS 仅在满足相关子查询(包含先前选择的值)时才更新该行,这意味着该行自上次读取以来尚未更新。如果它已被修改,则子查询匹配零行,并且不更新任何行。调用者必须检查有多少行受到影响才能知道是否应用了更新。以上是关于SQL触发器到应用程序[关闭]的主要内容,如果未能解决你的问题,请参考以下文章
PL/SQL 程序来计算年龄以及你的生日年份是不是是闰年[关闭]