Re: Record locking
The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration-id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration-id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a number of classifications which need to be looked up, anyways, editing this record can take upto 20 minutes. The size of this record certainly justifies breaking it up into a number of smaller records stored in separate tables, however the same problem remains because the user wants to see all of this information on 1 (scrollable) web page, we are still holding a lock on the information for the duration of the request. Potentially there are maybe 700 people who could be editing this record for different reasons. Accuracy of the information is critical - we don't want personal details being sent to a neighbour. The nature of the application means that users will be reviewing a record each year, and if any changes are made they are often made to the same record around the same time of the year - increasing the possibility of two people wanting to edit the record at the same time. Besides all of the above, the user has asked for exclusive editing of a record - such that other users can still read the existing record but nobody else can update the record while it is locked. The user understands the concept of networks issues and broken connections and therefore accepts a timeout condition on the lock of say 20 minutes. Next, how I will do
Re: Record locking
Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration-id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration-id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a number of classifications which need to be looked up, anyways, editing this record can take upto 20 minutes. The size of this record certainly justifies breaking it up into a number of smaller records stored in separate tables, however the same problem remains because the user wants to see all of this information on 1 (scrollable) web page, we are still holding a lock on the information for the duration of the request. Potentially there are maybe 700 people who could be editing this record for different reasons. Accuracy of the information is critical - we don't want personal details being sent to a neighbour. The nature of the application means that users will be reviewing a record each year, and if any changes are made they are often made to the same record around the same time of the year - increasing the possibility of two people wanting to edit the record at the same time. Besides all of the above, the user has asked for exclusive editing of a record - such that other users can still read the existing record but nobody else can update the record while it is locked. The
Re: Record locking
In my case, it was straightforward: the user is considered to be still editing if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over. Robert On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote: Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration-id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration-id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a number of classifications which need to be looked up, anyways, editing this record can take upto 20 minutes. The size of this record certainly justifies breaking it up into a number of smaller records stored in separate tables, however the same problem remains because the user wants to see all of this information on 1 (scrollable) web page, we are still holding a lock on the information for the duration of the request. Potentially there are maybe 700 people who could be editing this record for different reasons. Accuracy of the information is critical - we don't want personal details being sent to a neighbour. The nature of the application means that users will be reviewing a record each year, and if any changes are made
Re: Record locking
If the browser dies, then the session will timeout. The record will not stay locked (if you just keep an in-memory record of who is editing what). You could use a do you want to save your changes notification (a la GMail and others) to either save the data or send a request to clear the lock when they leave the edit screen. On 2/21/07, Andrea Chiumenti [EMAIL PROTECTED] wrote: ... But if the browser dies for some reason (very frequent especially with MS products), then the record will remain locked, the only possibility with this solution would be to add a locking timeout with application scope. On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: In my case, it was straightforward: the user is considered to be still editing if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over. Robert On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote: Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration-id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration-id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system
Re: Record locking
Actually, no, if the browser dies, the record won't stay locked. The updating happens from the edit page; if the browser crashes, there's no edit page, so no updating, so the lock expires. Cheers, Robert On Feb 21, 2007, at 2/214:03 AM , Andrea Chiumenti wrote: ... But if the browser dies for some reason (very frequent especially with MS products), then the record will remain locked, the only possibility with this solution would be to add a locking timeout with application scope. On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: In my case, it was straightforward: the user is considered to be still editing if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over. Robert On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote: Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration- id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration- id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a number of classifications which need to be looked up, anyways, editing this record can take upto 20 minutes. The size of this record certainly justifies breaking it up into a number of smaller
Re: Record locking
To clarify, by updating I'm referring to the ajax notifications that the user is still editing the object. Robert On Feb 21, 2007, at 2/215:50 AM , Robert Zeigler wrote: Actually, no, if the browser dies, the record won't stay locked. The updating happens from the edit page; if the browser crashes, there's no edit page, so no updating, so the lock expires. Cheers, Robert On Feb 21, 2007, at 2/214:03 AM , Andrea Chiumenti wrote: ... But if the browser dies for some reason (very frequent especially with MS products), then the record will remain locked, the only possibility with this solution would be to add a locking timeout with application scope. On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: In my case, it was straightforward: the user is considered to be still editing if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over. Robert On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote: Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration- id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration- id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a
Re: Record locking
Andrea, You can do this If you create a state object that has an application scope... you can wire your session listener to it to add and remove the session id's. state-object name=ApplicationManager scope=application Andrea Chiumenti wrote: But session is user specific and you want to lock the record accross the application, how whould you do this ? On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: Actually, no, if the browser dies, the record won't stay locked. The updating happens from the edit page; if the browser crashes, there's no edit page, so no updating, so the lock expires. Cheers, Robert On Feb 21, 2007, at 2/214:03 AM , Andrea Chiumenti wrote: ... But if the browser dies for some reason (very frequent especially with MS products), then the record will remain locked, the only possibility with this solution would be to add a locking timeout with application scope. On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: In my case, it was straightforward: the user is considered to be still editing if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over. Robert On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote: Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration- id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration- id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more
Re: Record locking
nice to know ;) On 2/21/07, Peter Stavrinides [EMAIL PROTECTED] wrote: Andrea, You can do this If you create a state object that has an application scope... you can wire your session listener to it to add and remove the session id's. state-object name=ApplicationManager scope=application Andrea Chiumenti wrote: But session is user specific and you want to lock the record accross the application, how whould you do this ? On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: Actually, no, if the browser dies, the record won't stay locked. The updating happens from the edit page; if the browser crashes, there's no edit page, so no updating, so the lock expires. Cheers, Robert On Feb 21, 2007, at 2/214:03 AM , Andrea Chiumenti wrote: ... But if the browser dies for some reason (very frequent especially with MS products), then the record will remain locked, the only possibility with this solution would be to add a locking timeout with application scope. On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: In my case, it was straightforward: the user is considered to be still editing if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over. Robert On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote: Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration- id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration- id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application
Re: Record locking
You use the session id so that you don't maintain the reference to the actual session. When the session listener sees that the session dies, he removes all object locks for that session. Now, this still doesn't solve the problem of one user opening multiple windows and trying to edit the same object, but if they're that stupid, then they deserve to lose their work (kidding of course, but just wanted to point out the issue). On 2/21/07, Andrea Chiumenti [EMAIL PROTECTED] wrote: nice to know ;) On 2/21/07, Peter Stavrinides [EMAIL PROTECTED] wrote: Andrea, You can do this If you create a state object that has an application scope... you can wire your session listener to it to add and remove the session id's. state-object name=ApplicationManager scope=application Andrea Chiumenti wrote: But session is user specific and you want to lock the record accross the application, how whould you do this ? On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: Actually, no, if the browser dies, the record won't stay locked. The updating happens from the edit page; if the browser crashes, there's no edit page, so no updating, so the lock expires. Cheers, Robert On Feb 21, 2007, at 2/214:03 AM , Andrea Chiumenti wrote: ... But if the browser dies for some reason (very frequent especially with MS products), then the record will remain locked, the only possibility with this solution would be to add a locking timeout with application scope. On 2/21/07, Robert Zeigler [EMAIL PROTECTED] wrote: In my case, it was straightforward: the user is considered to be still editing if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over. Robert On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote: Hi Robert I like your idea, you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing how exactly do you track if a user is still editing? Robert Zeigler wrote: The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid) Robert On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote: I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed
Re: Record locking
Leaving a database connection open for that period of time (possibly minutes/hours) isn't advisable from what I understand. On 2/19/07, Fred Janon [EMAIL PROTECTED] wrote: Yep, SELECT for UPDATE is what's behind TRANSACTION_SERIALIZABLE... On 2/20/07, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: How about using a SELECT . . . FOR UPDATE statement to select the record being edited. Once you read the record it will be locked, and as long as you keep the transaction open for the duration of the edit then no other transaction will be able to select the same record for update. If the transaction times out the DB management system will release the record for someone else to work with. Roland. If you stand up and be counted, from time to time you may get yourself knocked down. But remember this: A man flattened by an opponent can get up again. A man flattened by conformity stays down for good. - Thomas J. Watson, Jr. Fred Janon [EMAIL PROTECTED] wrote on 20/02/2007 10:44:20: Interesting question! I don't have any experience in doing this but it made me search in one of my Websphere book. Not sure if that would fulfill your requirements but TRANSACTION_SERIALIZABLE and PessimisticUpdate-Exclusive might be worth investigating. I am not sure what container you use and if JTA is available to you. I would check the JDBC driver as well, it might have some extra transaction support. Writing your own is probably pretty tempting when the answer is not obvious and you would know how it works. On the other side you have an extra write (at least) each time and need to manage the lock if the transaction is abandoned. If you have the time to investigate more, you'll probably a transaction guru soon. We, developers, have a tendency to avoid transactions and isolation levels like plague... Not easy development and test subjects as the lack of answers indicates... Good luck and let us know what solution you end up with, I am curious. Fred On 2/20/07, Murray Collingwood [EMAIL PROTECTED] wrote: James Carman james at carmanconsulting.com writes: You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. In an application where the user can spend 20 minutes completing the information in a row, they are not going to be happy when they find out somebody else has been updating this same row and the information has all been merged. They then spend another 10 minutes cleaning up all of the duplicated changes. Even pessimistic locking is not sufficient. I need guaranteed write-exclusive locking for the duration of the request. ie when I read-for-update the record should be locked against all other read-for-update requests until I save my changes and release the lock. It sounds as though I'm going to have to write my own...again. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Murray, I also have records that need to be 'checked out' for some time and your solution seems simple and elegant. So much so I may steal it. I use one sequence for every primary key in the database so a table named lock with key primary key timestamp timestamp userid should do it. UserId lets me know who has it. to see if a record is locked and get lock key select count(*) as locked, key, timestamp from lock where key = ? and timestamp less than 20 minutes old group by key, timestamp 1 is locked 0 unlocked timestamp is the key to lock the recored to lock a record if key == null insert into lock values ( key, now, userid) else update lock set timestamp = now, userid = ? where key = ? and timestamp = ? if you update 1 row you've got it otherwise someone else does to unlock update lock set timestamp = null where key = ? and timestamp = ? if you don't get 1 row updated something bad happened Seems easy. Records are locked a max of 20 minutes and no races I can see. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
The suggestion of using the http session (its id actually) was pretty cool I thought. That allows you to timeout the checkout/lock. You need to make sure (as pointed out) that the locks don't get orphaned, thereby locking everyone out of the object/record perpetually (obviously you could write an admin screen to unlock it). On 2/20/07, Barry Books [EMAIL PROTECTED] wrote: Murray, I also have records that need to be 'checked out' for some time and your solution seems simple and elegant. So much so I may steal it. I use one sequence for every primary key in the database so a table named lock with key primary key timestamp timestamp userid should do it. UserId lets me know who has it. to see if a record is locked and get lock key select count(*) as locked, key, timestamp from lock where key = ? and timestamp less than 20 minutes old group by key, timestamp 1 is locked 0 unlocked timestamp is the key to lock the recored to lock a record if key == null insert into lock values ( key, now, userid) else update lock set timestamp = now, userid = ? where key = ? and timestamp = ? if you update 1 row you've got it otherwise someone else does to unlock update lock set timestamp = null where key = ? and timestamp = ? if you don't get 1 row updated something bad happened Seems easy. Records are locked a max of 20 minutes and no races I can see. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Datebase timestamp seems better than a session id. Can't get perpetually locked and works outside a webserver session. - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a number of classifications which need to be looked up, anyways, editing this record can take upto 20 minutes. The size of this record certainly justifies breaking it up into a number of smaller records stored in separate tables, however the same problem remains because the user wants to see all of this information on 1 (scrollable) web page, we are still holding a lock on the information for the duration of the request. Potentially there are maybe 700 people who could be editing this record for different reasons. Accuracy of the information is critical - we don't want personal details being sent to a neighbour. The nature of the application means that users will be reviewing a record each year, and if any changes are made they are often made to the same record around the same time of the year - increasing the possibility of two people wanting to edit the record at the same time. Besides all of the above, the user has asked for exclusive editing of a record - such that other users can still read the existing record but nobody else can update the record while it is locked. The user understands the concept of networks issues and broken connections and therefore accepts a timeout condition on the lock of say 20 minutes. Next, how I will do this: 1. To establish a lock: a. I need a LOCK table: foreign-key, timestamp, userid b. In my Session I need a collection of timestamps c. Create a timestamp value - add it to my collection of timestamps d. Add a record to the LOCK table using my timestamp value e. Select from the lock table by foreign-key - if mine is the only record then read the record and begin editing, the lock was successful 2. Release the lock: (PS This is the difficult bit) a. Retrieve the LOCK records by foreign-key and userid, hopefully there should only be one. b. Check the timestamp value against my Session collection of timestamp values c. If the timestamp is in my collection then save the edited record and delete my LOCK record d. If the timestamp is not in my collection then the save has failed - tell the user gently 3. Dealing with an existing lock: a. While trying to establish a lock I find 2 LOCK records b. The latest record is mine, ignore that and look at the earlier record c. Look at the timestamp on the earlier record, if older than 20 minutes then delete this record and continue as normal d. Look at the userid on the earlier record, if it is mine then delete it and continue as normal (assumes my browser died, rebooted my computer, whatever, it's very typical for people to go straight back to what they were doing when their system crashed) e. If the timestamp is less than 20 minutes old then delete my LOCK record and report to the user that the record is locked by another user 4. You may want a maintenance process that cleans up broken locks, automatically deleting locks with a timestamp older than 24 hours. You could schedule this nightly or weekly - it's not critical. Why the collection of timestamps? 1. It allows the user to use the back button on the browser, either during editing or after editing (if it didn't save correctly the first time). 2. They might need to edit a related record in a different table as part of updating the main record - by storing each timestamp in a session collection we don't need to maintain these timestamps on our forms. Why add the lock record first? To avoid sequence problems like: a: User 1 looks for lock on id=1 - none found b: User 2 looks for lock on id=1 - none found c: User 1 adds a lock record d: user 2 adds a lock record Now the worst possible outcome is: a: User 1 adds a lock record on id=1 b: User 2 adds a lock record on id=1 c: Both users read and find two records with short timestamps - they are both informed the record is in use and to try again later - both records are deleted. Finally - the weakness: 1. The lock this gives you is only guaranteed for 20 minutes. Once that time is up somebody else can overwrite your lock with their own. It is better to set this timeout higher rather than lower. 2. You can overwrite your own lock. A user could open two browsers and edit the same record in each, the latter save overwriting the first. Hmmm, I think this comes under 'user error'. I think that explains it fairly well. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record. Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc. You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline: public class ApplicationManager { /** variable to store the singleton ApplicationManager */ private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager(); /** Hashtable containing visit history objects. String,Visit is the sessionid and the Visit Object */ private static ConcurrentHashMapString,Visit visitHistory_ = new ConcurrentHashMapString,Visit(); /** @return the ApplicationManager instance */ public synchronized static ApplicationManager getInstance(){ return applicationManagerInstance_; } } public class SessionMonitor implements HttpSessionListener { /** @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { String sid = event.getSession().getId(); ApplicationManager manager = ApplicationManager.getInstance(); manager.removeUserSession(sid); } Hivemodule.xml: contribution configuration-id=tapestry.state.ApplicationObjects state-object name=visit scope=session create-instance class=application.Visit/ /state-object /contribution contribution configuration-id=tapestry.state.ApplicationObjects state-object name=ApplicationManager scope=application create-instance class=application.ApplicationManager/ /state-object /contribution cheers, Peter Murray Collingwood wrote: Wow - what a lot of responses. First a little more detail - use case (for example): Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a number of classifications which need to be looked up, anyways, editing this record can take upto 20 minutes. The size of this record certainly justifies breaking it up into a number of smaller records stored in separate tables, however the same problem remains because the user wants to see all of this information on 1 (scrollable) web page, we are still holding a lock on the information for the duration of the request. Potentially there are maybe 700 people who could be editing this record for different reasons. Accuracy of the information is critical - we don't want personal details being sent to a neighbour. The nature of the application means that users will be reviewing a record each year, and if any changes are made they are often made to the same record around the same time of the year - increasing the possibility of two people wanting to edit the record at the same time. Besides all of the above, the user has asked for exclusive editing of a record - such that other users can still read the existing record but nobody else can update the record while it is locked. The user understands the concept of networks issues and broken connections and therefore accepts a timeout condition on the lock of say 20 minutes. Next, how I will do this: 1. To establish a lock: a. I need a LOCK table: foreign-key, timestamp, userid b. In my Session I need a collection of timestamps c. Create a timestamp value - add it to my collection of timestamps d. Add a record to the LOCK table using my timestamp value e. Select from the lock table by foreign-key - if mine is the only record then read the record and begin editing, the lock was successful 2. Release the lock: (PS This is the difficult bit) a. Retrieve the LOCK records by foreign-key and userid, hopefully there should only be one. b. Check the timestamp value against my Session collection of timestamp values c. If the timestamp is in my collection then save the edited record and delete my LOCK record d. If the timestamp is not in my collection then the save has failed - tell the user gently 3. Dealing with an existing lock: a. While trying to establish a lock I find 2 LOCK records b. The latest record is mine, ignore that and look at the
Re: Record locking
You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. On 2/19/07, Murray Collingwood [EMAIL PROTECTED] wrote: Hi Jesse Kuhnert jkuhnert at gmail.com writes: hibernate.org This is a rather simplistic answer, however I have been away and read the documentation and am not convinced that this is providing a method that will warn a user if somebody else if already updating a record. Even this example of pessimistic locking appears to allow for previous data changes to be overwritten: http://forum.springframework.org/archive/index.php/t-10188.html What would convince me? An example of a read-for-update operation that returned a condition (or exception) indicating that the requested object was currently locked by another user. I'm yet to find that in Hibernate. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
James Carman james at carmanconsulting.com writes: You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. In an application where the user can spend 20 minutes completing the information in a row, they are not going to be happy when they find out somebody else has been updating this same row and the information has all been merged. They then spend another 10 minutes cleaning up all of the duplicated changes. Even pessimistic locking is not sufficient. I need guaranteed write-exclusive locking for the duration of the request. ie when I read-for-update the record should be locked against all other read-for-update requests until I save my changes and release the lock. It sounds as though I'm going to have to write my own...again. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Interesting question! I don't have any experience in doing this but it made me search in one of my Websphere book. Not sure if that would fulfill your requirements but TRANSACTION_SERIALIZABLE and PessimisticUpdate-Exclusive might be worth investigating. I am not sure what container you use and if JTA is available to you. I would check the JDBC driver as well, it might have some extra transaction support. Writing your own is probably pretty tempting when the answer is not obvious and you would know how it works. On the other side you have an extra write (at least) each time and need to manage the lock if the transaction is abandoned. If you have the time to investigate more, you'll probably a transaction guru soon. We, developers, have a tendency to avoid transactions and isolation levels like plague... Not easy development and test subjects as the lack of answers indicates... Good luck and let us know what solution you end up with, I am curious. Fred On 2/20/07, Murray Collingwood [EMAIL PROTECTED] wrote: James Carman james at carmanconsulting.com writes: You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. In an application where the user can spend 20 minutes completing the information in a row, they are not going to be happy when they find out somebody else has been updating this same row and the information has all been merged. They then spend another 10 minutes cleaning up all of the duplicated changes. Even pessimistic locking is not sufficient. I need guaranteed write-exclusive locking for the duration of the request. ie when I read-for-update the record should be locked against all other read-for-update requests until I save my changes and release the lock. It sounds as though I'm going to have to write my own...again. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Just out of curiosity, can you tell more about your use case? I just have a hard time believing you'd need something like this for all of your tables - rather I'd assume it's something specific to a type of a record. And if it's the latter, I'd just implement it in the application level along the lines you'd suggested. But I'm not sure I'd call it locking, which I understand as a database feature for enforcing atomic transactions. It'd be fairly easy to implement the checking and enforcing of your edit rule in a Hibernate Interceptor. For obtaining the application level lock you can use optimistic locking; this is sort of the same as doing svn lock. Kalle On 2/19/07, Murray Collingwood [EMAIL PROTECTED] wrote: James Carman james at carmanconsulting.com writes: You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. In an application where the user can spend 20 minutes completing the information in a row, they are not going to be happy when they find out somebody else has been updating this same row and the information has all been merged. They then spend another 10 minutes cleaning up all of the duplicated changes. Even pessimistic locking is not sufficient. I need guaranteed write-exclusive locking for the duration of the request. ie when I read-for-update the record should be locked against all other read-for-update requests until I save my changes and release the lock. It sounds as though I'm going to have to write my own...again. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
I would say just put a property on the object that says that it has been checked out or something. That way, you can tell a user that tries to edit it that they can't because so and so has this record checked out and is editing it. On 2/19/07, Kalle Korhonen [EMAIL PROTECTED] wrote: Just out of curiosity, can you tell more about your use case? I just have a hard time believing you'd need something like this for all of your tables - rather I'd assume it's something specific to a type of a record. And if it's the latter, I'd just implement it in the application level along the lines you'd suggested. But I'm not sure I'd call it locking, which I understand as a database feature for enforcing atomic transactions. It'd be fairly easy to implement the checking and enforcing of your edit rule in a Hibernate Interceptor. For obtaining the application level lock you can use optimistic locking; this is sort of the same as doing svn lock. Kalle On 2/19/07, Murray Collingwood [EMAIL PROTECTED] wrote: James Carman james at carmanconsulting.com writes: You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. In an application where the user can spend 20 minutes completing the information in a row, they are not going to be happy when they find out somebody else has been updating this same row and the information has all been merged. They then spend another 10 minutes cleaning up all of the duplicated changes. Even pessimistic locking is not sufficient. I need guaranteed write-exclusive locking for the duration of the request. ie when I read-for-update the record should be locked against all other read-for-update requests until I save my changes and release the lock. It sounds as though I'm going to have to write my own...again. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
On Mon, Feb 19, 2007 at 08:17:02PM -0500, James Carman wrote: I would say just put a property on the object that says that it has been checked out or something. That way, you can tell a user that tries to edit it that they can't because so and so has this record checked out and is editing it. One has to be careful with this approach, because the checkout must, somehow, expire, otherwise you risk leaving an object permanently uneditable if a client gets disconected/forgotten/whatever. Just throwing random ideas about: How about making the 'checked-out' property a weak hash, pointing to the editing user's session (or some attribute within)? I assume the J2EE container will GC expired sessions, thus automatically expiring the object's check-out. -- Rodrigo Gallardo GPG-Fingerprint: 7C81 E60C 442E 8FBC D975 2F49 0199 8318 ADC9 BC28 Zenophobia: the irrational fear of convergent sequences. signature.asc Description: Digital signature
Re: Record locking
Just use the session id and set up an HttpSessionListener to remove user's locks when their session expires. On 2/19/07, Luis Rodrigo Gallardo Cruz [EMAIL PROTECTED] wrote: On Mon, Feb 19, 2007 at 08:17:02PM -0500, James Carman wrote: I would say just put a property on the object that says that it has been checked out or something. That way, you can tell a user that tries to edit it that they can't because so and so has this record checked out and is editing it. One has to be careful with this approach, because the checkout must, somehow, expire, otherwise you risk leaving an object permanently uneditable if a client gets disconected/forgotten/whatever. Just throwing random ideas about: How about making the 'checked-out' property a weak hash, pointing to the editing user's session (or some attribute within)? I assume the J2EE container will GC expired sessions, thus automatically expiring the object's check-out. -- Rodrigo Gallardo GPG-Fingerprint: 7C81 E60C 442E 8FBC D975 2F49 0199 8318 ADC9 BC28 Zenophobia: the irrational fear of convergent sequences. -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFF2k6xAZmDGK3JvCgRAnMJAJ9TFHFOmAlciwoY2kQO+rYdMBcvxgCffRk0 tl1+WX/ZP82yNXrwuELwhcA= =x6eX -END PGP SIGNATURE- - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Of course this all assumes that locking something is a good idea at all from a usability / scalability pov. There are rare occasions where it's needed but I'm skeptical nonetheless... At the very best you could do some kind of comet approach to letting the user know someone else is beginning (or is) also editing something. (like gmail showing that yellow box when someone else is replying to the same email thread) It's a big can of worms. On 2/19/07, James Carman [EMAIL PROTECTED] wrote: Just use the session id and set up an HttpSessionListener to remove user's locks when their session expires. On 2/19/07, Luis Rodrigo Gallardo Cruz [EMAIL PROTECTED] wrote: On Mon, Feb 19, 2007 at 08:17:02PM -0500, James Carman wrote: I would say just put a property on the object that says that it has been checked out or something. That way, you can tell a user that tries to edit it that they can't because so and so has this record checked out and is editing it. One has to be careful with this approach, because the checkout must, somehow, expire, otherwise you risk leaving an object permanently uneditable if a client gets disconected/forgotten/whatever. Just throwing random ideas about: How about making the 'checked-out' property a weak hash, pointing to the editing user's session (or some attribute within)? I assume the J2EE container will GC expired sessions, thus automatically expiring the object's check-out. -- Rodrigo Gallardo GPG-Fingerprint: 7C81 E60C 442E 8FBC D975 2F49 0199 8318 ADC9 BC28 Zenophobia: the irrational fear of convergent sequences. -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFF2k6xAZmDGK3JvCgRAnMJAJ9TFHFOmAlciwoY2kQO+rYdMBcvxgCffRk0 tl1+WX/ZP82yNXrwuELwhcA= =x6eX -END PGP SIGNATURE- - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] -- Jesse Kuhnert Tapestry/Dojo team member/developer Open source based consulting work centered around dojo/tapestry/tacos/hivemind. http://blog.opencomponentry.com - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
How about using a SELECT . . . FOR UPDATE statement to select the record being edited. Once you read the record it will be locked, and as long as you keep the transaction open for the duration of the edit then no other transaction will be able to select the same record for update. If the transaction times out the DB management system will release the record for someone else to work with. Roland. If you stand up and be counted, from time to time you may get yourself knocked down. But remember this: A man flattened by an opponent can get up again. A man flattened by conformity stays down for good. - Thomas J. Watson, Jr. Fred Janon [EMAIL PROTECTED] wrote on 20/02/2007 10:44:20: Interesting question! I don't have any experience in doing this but it made me search in one of my Websphere book. Not sure if that would fulfill your requirements but TRANSACTION_SERIALIZABLE and PessimisticUpdate-Exclusive might be worth investigating. I am not sure what container you use and if JTA is available to you. I would check the JDBC driver as well, it might have some extra transaction support. Writing your own is probably pretty tempting when the answer is not obvious and you would know how it works. On the other side you have an extra write (at least) each time and need to manage the lock if the transaction is abandoned. If you have the time to investigate more, you'll probably a transaction guru soon. We, developers, have a tendency to avoid transactions and isolation levels like plague... Not easy development and test subjects as the lack of answers indicates... Good luck and let us know what solution you end up with, I am curious. Fred On 2/20/07, Murray Collingwood [EMAIL PROTECTED] wrote: James Carman james at carmanconsulting.com writes: You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. In an application where the user can spend 20 minutes completing the information in a row, they are not going to be happy when they find out somebody else has been updating this same row and the information has all been merged. They then spend another 10 minutes cleaning up all of the duplicated changes. Even pessimistic locking is not sufficient. I need guaranteed write-exclusive locking for the duration of the request. ie when I read-for-update the record should be locked against all other read-for-update requests until I save my changes and release the lock. It sounds as though I'm going to have to write my own...again. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Yep, SELECT for UPDATE is what's behind TRANSACTION_SERIALIZABLE... On 2/20/07, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: How about using a SELECT . . . FOR UPDATE statement to select the record being edited. Once you read the record it will be locked, and as long as you keep the transaction open for the duration of the edit then no other transaction will be able to select the same record for update. If the transaction times out the DB management system will release the record for someone else to work with. Roland. If you stand up and be counted, from time to time you may get yourself knocked down. But remember this: A man flattened by an opponent can get up again. A man flattened by conformity stays down for good. - Thomas J. Watson, Jr. Fred Janon [EMAIL PROTECTED] wrote on 20/02/2007 10:44:20: Interesting question! I don't have any experience in doing this but it made me search in one of my Websphere book. Not sure if that would fulfill your requirements but TRANSACTION_SERIALIZABLE and PessimisticUpdate-Exclusive might be worth investigating. I am not sure what container you use and if JTA is available to you. I would check the JDBC driver as well, it might have some extra transaction support. Writing your own is probably pretty tempting when the answer is not obvious and you would know how it works. On the other side you have an extra write (at least) each time and need to manage the lock if the transaction is abandoned. If you have the time to investigate more, you'll probably a transaction guru soon. We, developers, have a tendency to avoid transactions and isolation levels like plague... Not easy development and test subjects as the lack of answers indicates... Good luck and let us know what solution you end up with, I am curious. Fred On 2/20/07, Murray Collingwood [EMAIL PROTECTED] wrote: James Carman james at carmanconsulting.com writes: You can use optimistic locking. When the user submits and they have outdated data, then you just merge the object's data with what is in the data store and show it back to the user for them to confirm it. In an application where the user can spend 20 minutes completing the information in a row, they are not going to be happy when they find out somebody else has been updating this same row and the information has all been merged. They then spend another 10 minutes cleaning up all of the duplicated changes. Even pessimistic locking is not sufficient. I need guaranteed write-exclusive locking for the duration of the request. ie when I read-for-update the record should be locked against all other read-for-update requests until I save my changes and release the lock. It sounds as though I'm going to have to write my own...again. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
hibernate.org On 2/18/07, Murray Collingwood [EMAIL PROTECTED] wrote: Hi all Many years ago I wrote a web application that utilitised a proprietary database. The database supported record locking however it was not suitable for a web application. So, I wrote a facility I called 'Long Locks'. It required a timestamp field be added to each table. When a web user wanted to edit a record they would check if the timestamp field was null, if so they wrote a timestamp into the record and sent this along with the data to the user (the timestamp was not visible by the user). After they had completed updating the details (which could take upto 20 minutes) they could then save the record, the timestamp would be compared with the entry on the record and if they matched the update would be committed. This enabled a number of key features: 1. I was able to guarantee write access for a user when they requested a record for update. (If the record was already long-locked I would inform the user the record was locked by another user). 2. I was always able to read the record 3. If a user abandoned a long-locked record the lock would eventually expire (we set this to 20 minutes for our application) I have been reading through a number of record-locking strategies but it seems most of them are optimistic in that they hope nobody else has updated the record since it was read, and in the event that it was all of your changes are lost. This is very frustrating for the user has just spent 20 minutes entering data! I'm happy to write my own locking system again. I was just wondering if anybody knew of a better way - something to save me writing my own system again? Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] -- Jesse Kuhnert Tapestry/Dojo team member/developer Open source based consulting work centered around dojo/tapestry/tacos/hivemind. http://blog.opencomponentry.com - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: Record locking
Hi Jesse Kuhnert jkuhnert at gmail.com writes: hibernate.org This is a rather simplistic answer, however I have been away and read the documentation and am not convinced that this is providing a method that will warn a user if somebody else if already updating a record. Even this example of pessimistic locking appears to allow for previous data changes to be overwritten: http://forum.springframework.org/archive/index.php/t-10188.html What would convince me? An example of a read-for-update operation that returned a condition (or exception) indicating that the requested object was currently locked by another user. I'm yet to find that in Hibernate. Cheers mc - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]