检票口、身份验证和交易界定
我将 Wicket 与自定义 PageAuthorizationStrategy 结合使用,该策略访问数据库以获取有关当前用户及其访问权限的信息。每个请求都由 Spring Open-Session-In-View 过滤器包装以打开/关闭 Hibernate 会话。
这非常适合对数据库的读取访问。每当需要进行写入操作时,我都会调用使用 Spring 基于注释的事务处理的服务层。这也有效,但我认为这是导致特定错误的原因:当在请求 A 中的身份验证期间加载对象,然后在另一个请求 B 中修改,然后在请求 A 中移交给服务层时,服务层正在处理错误的值,因为 Hibernate 和底层数据库都无法确保隔离。由于我总是在数据库/事务理论的细节上遇到一些困难,如果这个假设已经错误,请纠正我。
我的解决方案的第一个想法是在写入事务开始后立即刷新加载的对象以进行身份验证。但是,当服务要修改的对象同时需要进行身份验证时,这会导致问题。当 Wicket 使用表单中更改的数据填充对象并将其传递到提交方法中的服务时(例如),尤其会发生这种情况。
因此,正确的方法可能是确保身份验证代码已经与可能在同一请求期间执行的任何写入代码包装在同一事务中。
我将如何在 Wicket 中以“正确的方式”解决这个问题?
编辑:这个问题变得更加严重,因为我意识到当事务服务方法在抛出异常后回滚时,视图层会导致 LazyInitializationException。显然,Spring 的 TransactionManager 会清除会话和/或 Hibernate/Spring 深处的其他内容出错,因为我可以从数据库重新加载对象,但尝试加载该对象中包含的集合会导致所述异常。有什么想法如何解决这个问题吗?我想如果有一种优雅的方式来使用“每个请求一个事务”,那么这一切都会得到解决。
I am using Wicket with a custom PageAuthorizationStrategy which accesses the database for information on the current user and thereby his access permissions. Every request is wrapped by the Spring Open-Session-In-View filter to open/close the Hibernate session.
This works perfectly for reading access to the database. Whenever writing operations need to take place though, I call the service layer which uses Spring's annotation-based transaction handling. This also works BUT I think it is the cause for a particular bug: When an object is loaded during authentication in request A, then modified in another request B and then handed over to the service layer in request A, the service layer is working with wrong values since neither Hibernate nor the underlying database can ensure isolation. Since I'm always struggling a bit with specifics of database/transaction theory, please correct me if this assumption is already wrong.
My first idea for a solution was to refresh the objects loaded for authentication right after a writing transaction had been started. This causes issues though when an object to be modified by the service is at the same time needed for authentication. This especially happens when Wicket populates an object with changed data from a form and it is passed to the service in a submit method (for example).
So probably, the correct way of doing this would be to ensure that the authentication code is already wrapped in the same transaction as any writing code that might be executed during the same request.
How would I go about this the "right way" in Wicket?
EDIT: This problem just became even more of an issue as I realized that when the transactioned service method rolls back after an exception is thrown, the view layer causes a LazyInitializationException. Obviously, Spring's TransactionManager clears the session and/or something else in the depths of Hibernate/Spring goes wrong as I can reload an object from the database but trying to load a collection contained in that object causes said exception. Any ideas how to go about this? I suppose it would all be solved if there was an elegant way to use "one-transaction-per-request".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这不是 Wicket 问题,而是 DB/Hibernate 问题。 Hibernate 支持乐观和悲观策略。
乐观方法包括向实体添加一个
version
字段,该字段将在刷新更新时进行验证,如果记录已被某人修改,则会引发异常。悲观方法使用数据库支持锁定记录,避免并发修改。
两者都有优点和缺点,并且都需要您积极使用相应的功能和代码才能使其工作(没有魔法灰尘)。
乐观者必须处理所有可能出现的异常情况。
悲观主义者将不得不处理争用和可扩展性问题。
乐观者可能必须更改模式结构和/或域模型来处理某些情况。
悲观主义者在处理该表的更新时必须始终担心锁定(您忘记锁定在一个地方,并且您刚刚创建了一个 heisenbug)。
NoSQL 人员会告诉他们完全放弃关系数据库,在没有模式、事务和一致性的情况下快乐地生活(顺便说一句,这在大多数情况下是愚蠢的)。
This is not a Wicket issue, but a DB/Hibernate issue. Hibernate has support for both optimistic and pessimistic strategies.
The optimistic approach consists in adding a
version
field to the entity, which will be verified when flushing an update, and cause an exception if the record've been modified by someone.The pessimistic approach uses database support to lock the record, avoiding concurrent modifications.
Both have pros and cons, and both will require you to actively use the features and code accordingly to make it work (no magic dust).
The optimist will have to handle exceptions everywhere they may arise.
The pessimist will have to deal with contention and scalability issues.
The optimist may have to change the schema structure and/or the domain model to handle some cases.
The pessimist will have to always worry about locking when dealing with updates to that table (you forget to lock in one place, and you've just created a heisenbug).
And the NoSQL folks will tell them to drop relational databases altogether, and live happily without schemas, transactions and consistence (which in most cases is stupid, by the way).
我不确定这是否是 Wicket 中“正确方法”的问题,我会尝试在服务/dao 层中解决此问题,有一些可能性,例如:
i am not sure if this is even a question for the "right way" in Wicket, i would try to solve this in the service/dao layer, there are some possibilities like: