数据访问对象 (DAO) 如何允许同时更新列的子集?
How Can a Data Access Object (DAO) Allow Simultaneous Updates to a Subset of Columns?
如果我误用了任何 OOP 术语,请原谅我,因为我对这个主题还不太了解。
我一直在阅读面向对象编程 (OOP) - 特别是针对 Web 应用程序。我一直在研究数据访问对象 (DAO) 的概念。 DAO 负责 CRUD(创建、读取、更新和删除)方法并将应用程序的服务(业务逻辑)层连接到数据库。
我的问题具体涉及 DAO 中的 Update()
方法。在我读过的示例中,开发人员通常将一个 bean 对象作为其主要参数传递给 DAO update()
方法 updateCustomer(customerBean)
该方法然后执行一些 SQL 更新所有基于关于bean中的数据。
我看到的这个逻辑的问题是 update()
方法根据 bean 的数据更新数据库中的 ALL 列,理论上可能会导致它覆盖列另一个用户或系统可能需要同时更新。
一个简化的例子可能是:
- 用户 1 更新 bean 中的字段 A
- 用户 2 更新 bean 中的字段 B
- 用户 2 将 bean 传递给 DAO,DAO 更新所有字段。
- 用户 1 将 bean 传递给 DAO,DAO 更新所有字段。
- 用户 2 的更改已丢失!
我读过 乐观锁定 和 悲观锁定 作为一次只允许一个更新的可能解决方案,但我认为在许多情况下,应用程序 需要 允许同时编辑记录的不同部分而不会锁定或引发错误。
例如,假设管理员正在更新客户的 lastName
,同时客户登录网站,登录系统需要更新 dateLastLoggedIn
列,同时计划任务需要更新 lastPaymentReminderDate
。在这个疯狂的例子中,如果您将一个 bean 对象传递给 update()
方法并每次都保存整个数据记录,那么无论哪个进程最后运行 update()
方法都可能会覆盖所有数据。
肯定有办法解决这个问题。根据我的研究,我提出了一些可能性,但我很想知道 proper/best 实现这一目标的方法。
可能的解决方案 1:DAO Update()
方法不接受 Bean 作为参数
如果 update()
方法接受一种数据结构,其中包含数据库中需要更新的所有列而不是 bean 对象,您可以使 SQL 语句足够智能,只更新传递给方法的字段。例如,参数可能如下所示:
{
customerID: 1,
firstName: 'John'
}
这基本上会告诉 update()
方法仅更新基于 customerID
的列 firstName
,1. 这将使您的 DAO 非常灵活,并会给服务层与数据库动态交互的能力。我有一种直觉,这违反了 OOP 的某些 "golden rule",但我不确定是哪个。我也从来没有在网上看到任何 DAO 行为的例子。
可能的解决方案 2:向您的 DAO 添加额外的 update()
方法。
您还可以通过向 DAO 添加更具体的 update()
方法来解决此问题。例如,您可能有一个 dateLastLoggedIn()' and 'dateLastPaymentReminderDate()
。这样,理论上每个需要更新记录的服务都可以同时进行。如果需要,可以为每个特定的更新方法进行任何锁定。
这种方法的主要缺点是您的 DAO 将开始因各种更新语句而变得非常混乱,而且我看到许多博客文章都在写 DAO 会很快变得多么混乱。
假设您需要允许同时更新记录数据的子集,您将如何使用 DAO 对象解决此类难题?您会坚持将 bean 传递给 DAO 还是有其他我没有考虑过的解决方案?
如果您对 returns 一个 bean 执行 DAO.read() 操作,然后使用用户的新值更新 bean,然后将该 bean 传递给 DAO.update(bean)方法,那么你应该不会有问题,除非两个用户操作发生在彼此的几毫秒内。您的问题暗示 bean 在传递给 update() 方法之前被存储在会话范围或类似范围内。如果那是您正在做的事情,请不要这样做,原因正是您所描述的。您不希望您的 bean 与数据库记录不同步。为了更好的安全性,围绕读取和更新操作包装一个事务,那么两个用户就不可能踩到对方的脚趾,即使用户 2 与用户 1 在同一时间提交他的更改。
Read()、设置值、update() 是我认为的方法。保持豆子新鲜。没有人想要陈旧的豆子。
如果我误用了任何 OOP 术语,请原谅我,因为我对这个主题还不太了解。
我一直在阅读面向对象编程 (OOP) - 特别是针对 Web 应用程序。我一直在研究数据访问对象 (DAO) 的概念。 DAO 负责 CRUD(创建、读取、更新和删除)方法并将应用程序的服务(业务逻辑)层连接到数据库。
我的问题具体涉及 DAO 中的 Update()
方法。在我读过的示例中,开发人员通常将一个 bean 对象作为其主要参数传递给 DAO update()
方法 updateCustomer(customerBean)
该方法然后执行一些 SQL 更新所有基于关于bean中的数据。
我看到的这个逻辑的问题是 update()
方法根据 bean 的数据更新数据库中的 ALL 列,理论上可能会导致它覆盖列另一个用户或系统可能需要同时更新。
一个简化的例子可能是:
- 用户 1 更新 bean 中的字段 A
- 用户 2 更新 bean 中的字段 B
- 用户 2 将 bean 传递给 DAO,DAO 更新所有字段。
- 用户 1 将 bean 传递给 DAO,DAO 更新所有字段。
- 用户 2 的更改已丢失!
我读过 乐观锁定 和 悲观锁定 作为一次只允许一个更新的可能解决方案,但我认为在许多情况下,应用程序 需要 允许同时编辑记录的不同部分而不会锁定或引发错误。
例如,假设管理员正在更新客户的 lastName
,同时客户登录网站,登录系统需要更新 dateLastLoggedIn
列,同时计划任务需要更新 lastPaymentReminderDate
。在这个疯狂的例子中,如果您将一个 bean 对象传递给 update()
方法并每次都保存整个数据记录,那么无论哪个进程最后运行 update()
方法都可能会覆盖所有数据。
肯定有办法解决这个问题。根据我的研究,我提出了一些可能性,但我很想知道 proper/best 实现这一目标的方法。
可能的解决方案 1:DAO Update()
方法不接受 Bean 作为参数
如果 update()
方法接受一种数据结构,其中包含数据库中需要更新的所有列而不是 bean 对象,您可以使 SQL 语句足够智能,只更新传递给方法的字段。例如,参数可能如下所示:
{
customerID: 1,
firstName: 'John'
}
这基本上会告诉 update()
方法仅更新基于 customerID
的列 firstName
,1. 这将使您的 DAO 非常灵活,并会给服务层与数据库动态交互的能力。我有一种直觉,这违反了 OOP 的某些 "golden rule",但我不确定是哪个。我也从来没有在网上看到任何 DAO 行为的例子。
可能的解决方案 2:向您的 DAO 添加额外的 update()
方法。
您还可以通过向 DAO 添加更具体的 update()
方法来解决此问题。例如,您可能有一个 dateLastLoggedIn()' and 'dateLastPaymentReminderDate()
。这样,理论上每个需要更新记录的服务都可以同时进行。如果需要,可以为每个特定的更新方法进行任何锁定。
这种方法的主要缺点是您的 DAO 将开始因各种更新语句而变得非常混乱,而且我看到许多博客文章都在写 DAO 会很快变得多么混乱。
假设您需要允许同时更新记录数据的子集,您将如何使用 DAO 对象解决此类难题?您会坚持将 bean 传递给 DAO 还是有其他我没有考虑过的解决方案?
如果您对 returns 一个 bean 执行 DAO.read() 操作,然后使用用户的新值更新 bean,然后将该 bean 传递给 DAO.update(bean)方法,那么你应该不会有问题,除非两个用户操作发生在彼此的几毫秒内。您的问题暗示 bean 在传递给 update() 方法之前被存储在会话范围或类似范围内。如果那是您正在做的事情,请不要这样做,原因正是您所描述的。您不希望您的 bean 与数据库记录不同步。为了更好的安全性,围绕读取和更新操作包装一个事务,那么两个用户就不可能踩到对方的脚趾,即使用户 2 与用户 1 在同一时间提交他的更改。
Read()、设置值、update() 是我认为的方法。保持豆子新鲜。没有人想要陈旧的豆子。