Wicket, authentication and transaction demarcation
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 th开发者_如何学运维at 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".
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).
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:
- do not use OSIV pattern for information which is needed in "real time", OSIV shines, when used on tables to display item information without the need to query the database
- attach edited/changed attributes to the object e.g. the timestamp of the last change, before any write operation you could check the timestamps and warn/compensate changes from the "future"
精彩评论