【发布时间】:2012-11-14 09:59:06
【问题描述】:
我有一个后端应用程序,该应用程序没有任何用户界面。这些操作由服务器在 UDP 和 TCP 端口上侦听的传入数据触发。
我们有 Customer 表,该表有 15 个字段。每个字段代表一些关键细节或指向其他信息的指针。例如,
CUSTOMER_TABLE {
ID,
NAME,
DEFAULT_ADDRESS_ID,
EMAIL_ADDRESS,
LAST_LOGIN,
VERSION <--- trying to introduce
}
除了 ID 之外,这些字段中的每一个都可以由不同的进程一次更新。当两个并发进程覆盖彼此的值时,我遇到了问题。所以,我介绍了 VERSION - hibernate 生成的版本字段。
现在假设服务器 1 在时间 T1 获取带有版本#400 的客户模型 Server2 在 T1 时获取版本#400 的 Customer 模型
Server1 更改 EMAIL_ADDRESS 并更新 CUSTOMER(在 T2),因此新版本号为 401(休眠生成)。
Server2 更改 NAME 并尝试在 T3 更新 CUSTOMER,由于版本号比 DB 中的版本号旧,因此事务将失败。
由于应用程序是非用户界面应用程序,我们不能真正要求用户授权更改...我们必须优雅地处理它,以便更改通过。
我有什么办法来处理这种情况?
该应用具有以下结构
Listening Port Handler -> Service Wrapped in Transaction -> DAO -> DB
对于下一个 - 这是一个免责声明 - 我知道这是一个糟糕的设计......但不幸的是,该应用程序已经从一个非事务性应用程序以一种非常无计划的方式发展为事务性应用程序......我在决定“何时”修复整体设计时没有太多控制权。现在的结构....
Listening Port Handler -> Service invoked to get the model(ModelX) -> DAO -> DB (yes you are right, the model goes out of transaction boundary ... :-( )
-> Invoke different independent operations, each operation wrapped in txn -> DAO -> DB
-> Modify Model (ModelX)
-> Update model(ModelX) as a separate transaction -> DAO -> DB
我在第二个中会遇到问题,我无法刷新我的模型,因为如果我这样做了,我将丢失在模型上更改的所有内容,或者我将不得不再次重复所有步骤,这可能会导致其他成功的操作触发了两次(至少)
我的问题是 - 无论如何
- hibernate 可以理解被修改的属性
- 检查版本
- 如果现有版本过时,请获取新版本并在新版本上应用更改
- 保存对象(而不是抛出异常)
【问题讨论】:
-
i) 如果您不想要旧数据,请同步您的方法。 ii) 或者您可以在抛出异常时重试该操作。但是您必须自己编写此逻辑。
-
@TJ - 感谢您的回复 i)如果它是单一服务器环境,同步会有所帮助......但不幸的是,它是一个多服务器环境。 ii)要编写自定义逻辑,我将不得不放置一个事务异常处理程序并依赖于异常和抛出它的位置......呃......我的生命将结束,然后我才能想到完成这个功能更改。所以....您是说休眠无法理解问题(内省修改后的模型)并将更改应用于最新模型?
标签: java hibernate backend spring-transactions application-design