Is there a way to lock a record in a MySQL table for a specific period of time? - mysql

Friends,
I have a table that contains data on the two parents of students at a college. Each parent will be sent an email with a link to a web page that will display the parent data that we currently have on record (names, email addresses, mailing addresses, employment information, etc.), and will be able to edit the data in order to update our records.
Since each parent will receive a link to the same data, and will be able to update the same fields, there is the potential for both parents opening the data at the same time, and then one parent submitting changes, then the other submitting changes which would overwrite those submitted by the first parent.
In order to avoid this, I have thought of using the method I've read about in which a timestamp field exists in the parent data record, and that timestamp is used as a hidden field on the form. Then, if both parents load the form, they'll both have the same timestamp stored in the form. When the first parent submits her/his updates, though, the timestamp field will update, and when the form is submitted by the second parent, the timestamp from her/his form will not be the same as the timestamp in the table, and the program (a Perl CGI) would alert the 2nd parent to this fact, and tell them to reload the form or risk overwriting the data submitted by the first parent.
That will work, but the person for whom I'm creating this form has asked if, instead, there's a way to lock the record in the table as soon as the first parent loads the form, and if the second parent tries to load the form while the lock exists, the form will tell them to wait until later (or words to that effect). The lock would be in place either until the form is submitted by parent one, or until one hour (or some specific period of time) has passed. Is this even do-able? I've been Googling, and don't see specific examples of this having been done.
Is there some better solution to this issue of needing to prevent two people from updating the same record, and the second submitter overwriting data submitted by the first.
Thanks for any help you can provide!
Doug
*******to address the comment by "inspiredcoder," here are some more details about what I'm concerned with here:
What I'm trying to avoid having happen is that parent 1 opens the form and starts making changes to the data. Before parent 1 submits those changes, parent 2 opens the form and also starts making different changes to the same fields being edited by parent 1. Parent 1 then submits her/his changes. Parent 2 then submits her/his changes, overwriting the changes made by parent 1.
What I would prefer is that parent 2 would not be able to even begin making changes if parent 1 has opened the form. The changes made by both parents need to be captured, and not overwritten.
The method of using the timestamp as I describe in my initial post can be used to prevent parent 2 from overwriting the data, but it also will mean that they'd have to reload the form to see the changes submitted by parent 1, and in doing so, would lose any of the edits they'd made in the form prior to them trying to submit it and getting the notice to reload. I'd like to avoid them having to re-enter their changes, and the only way to accomplish this seems to be to prevent them from even opening the form if it is already being edited, but I'd want that "lock" on the form/data to timeout after an hour or so in case parent 1 walks away with the form open but unsubmitted.
*****To answer a question by "ThisSuitIsBlackNot": Each parent can edit the same fields. One field asks for activities in which the parents are involved. Let's say Parent 1 enters five activities. If Parent 2 sees the form before Parent 1's edits have been submitted, he/she may enter completely different items, which upon submission would overwrite the activities submitted by Parent 1. If, on the other hand, Parent 2 could be stopped from accessing the form until after Parent 1 has finished her/his edits, then when Parent 2 can load the form, she/he will see everything that Parent 1 entered, rather than an empty form field, and may choose to modify what Parent 1 submitted, overwrite it completely, or not make any changes.

There's a reason you're not finding any info on how to do this. It is a very tough problem that no one has a good solution for regardless of which tech stack you're using. In your case, I'm not convinced that it is actually a terribly important issue to solve because the data does not seem crucial or mission critical. And besides, if there are changes they will likely be the same.
I've been in many design discussions where this issue came up. After hours of arguing the result is always the same: Last one in wins.
That said, here are a couple of simpler ideas you could try:
Simply email both parents (or whoever's registered as a guardian) whenever data on that page changes. This solution is stupid simple and easy to implement. If you're already using email services in other parts of the app then it becomes nearly trivial.
Not so simple: Whenever a request is made to edit the data, create a hash of the data as is to send back with the response to the client. When the edited data is sent in to update the row, check the data against the hash. If the hashes don't match it means that someone else has modified the data while the other parent was looking at it. The trouble with this solution is that you have to create these hashes and lug them around through several layers of the app making your programming non-trivial.
This statement caught my eye in a later edit of your OP:
The changes made by both parents need to be captured, and not
overwritten.
That single business rule actually makes things quite simple for you. All you need to do is to ALWAYS create objects when they do not have a unique identifier (probably 0 or -1). When objects do have an ID, meaning they have already been created, you simply update.
There is an assumption here that edits will likely be performed non-destructively on the same data. e.g. One parent creating an activity and the other parent editing it. There is a chance of duplicate activities but that's a situation easily resolved with a delete.
This way, no one parent can overwrite the other's data blindly and unknowingly.
Regardless of what you do though, do not try to find a perfect solution. It just doesn't happen. I know, I've been writing line of business apps for over 15 years. Apply your time and talents to something that you can get right, which the application and its business rules.

I would suggest reading up on database isolation levels. I believe MySQL defaults to repeatable read. You can confirm your isolation level at the DB level by running "SHOW GLOBAL VARIABLES LIKE 'tx_isolation';" Each transaction in this configuration is already placing a lock. Whether it is getting a row level or escalating depends on factors such as how indexes are being hit etc, by the query. If you fire off transaction A to update a record then subsequently fire off transaction B, transaction B is already in a holding pattern until transaction A completes its work in this configuration. If you set this to read commited, reads no longer block each other with locking (updates, etc still place locks). In lieu of implicit locks on reads you can be explicit using the select for update to try and force a lock on the read.
I mention brushing up on locking mechanics as trying to brute force locking without extreme knowledge of the back end DB mechanics can lend itself to deadlock central.
It seems like in your scenario this is more about user perception that what they are reading is up to date when they submit the changes. The DB is really doing it's job as designed. I have seen architecture to address this user perception issue by only allowing one user in a record at a time (locking out other users from the record while someone is it) handled in some middle ware code, etc. Or by using SOA architecture to push notifications to users in the record that a changed occurred by another user.

Related

Main form mislinking to subform after switching to Sharepoint back end - MS Access

Why would my form/subform mislink records using SharePoint List back end?
I have years of experience with MS Access, but this is my first time with SharePoint List as a back end.
I developed a small database for a small non-profit. Started off with Access 365 front end and back end, located on one user's computer. This ran fine and correctly for a few months, and last month we migrated the back end to SharePoint Lists so that two other users can use the database. They each have the front end on their desktop.
There's a bound form, Events, linked to tblEvents. Subform, subVolTime, on this form is linked to tblVolTime, to show the volunteers and how much time they spent at the event. In the subform property, Link Master Fields is set to tblEvents.ID; Link Child Fields is set to tblVolTime.EventID. There's no extra VBA code.
We migrated to SharePoint Lists using the wizards, and did nothing else. Shortly afterwards, my user noticed that the wrong people were showing up under events. He can tell just by looking at the names.
I created an audit query, and I can see that in some cases the dateAdded (date the record was created) in tblVolTime is BEFORE the dateAdded of the event in tblEvent. This can't be right, because you must have a record in tblEvent before an associated record in tblVolTime.
For example, there's an event ID 261, created on 4 Nov 2021. The records for the volunteers linked with this eventID were created 7 Oct 2021. Something went wonky.
Any suggestions are welcome. My ideas include: unbind the form; hide the subform until the event record is saved; create the event record before the user actually adds any data to it.
Well, hard to tell. However, unlike moving Access data say to SQL server?
Moving data up to SharePoint is VERY MUCH a different process. Why?
Well, for one, when moving data to SharePoint, the auto number PK's you have (and you MUST HAVE FOR ALL TABLES) are often re-numbered.
Now, due to this re-numbering of auto numbers?
Well, that means before you migrate the data, you BETTER really, but really and beyond really sure that a relationship was setup between such tables.
In the case of Access, while in most cases we do have a correctly setup relatonship, to be honest, you REALLY never had to do that. In other words, if I setup a master link and child link for a sub form? Well, access would just generate the PK autonumbers for the main table, generate the pk autonumbers for the child table. And THEN during a data insert would correctly insert/set the "FK" values in that child table to the parent table. As long as the link master/child settings were correctly setup (but no actual relationship was setup), then the application would happy work.
If one was to migrate the data to say SQL server? Well, since the PK autonumbers are NOT touched during this up-load process - then all relationships and their data would ALSO make a valid trip up to SQL server.
However, in the case of SharePoint? Autonumbers for ALL tables are and will and in most cases are re-generated!!!!
But, this tends to not be a problem if you up-sized the data using Access. It has built in SharePoint support, and say if a parent reocrd goes up from Access to sharepoint and the PK id is changed? No probem, since if you REALLY did setup,and you REALLY did have a relatonship setup, then the migration process is smart enough to go find the child reocrds, and update the FK values. But of course the migration process can ONLY do this magic trick if you KNOWS about the realationship.
Another simple example?
Say we have a simple form, and we have a SMIPLE combo box to pick say favor color.
tbColors
ID (Auto number PK).
Color (text color).
So, so now we have a simple form, and we dropped in a combo box. When we choose a simple color like "red" or "blue" from the combo, we of course are saving the "pk" id from the above table.
Now for a LOT of simple tables like above, never used, or bothered with setting up a realtonship. (no need - just a few choices from a combo box).
And if you were up-size data to sql server? Again, this would work fine - no problem at all.
However, if you up-size to SharePoint? You REALLY but REALLY better have setup a relationship even for this simple silly little combo box. Again, the reason is simple. When that simple table of pick list values goes up to SharePoint, the autonumber PK id's will change. And thus for any other table that used that simple pick list? You have and MUST have setup in your relationships window that this was in fact the relationships - and again, the reason is re-numbering of autonumbers.
So for ANY relationships that used PK and FK values? They MUST in ALL cases when using SharePoint MUST have been defined in the access data tables (relationships window) BEFORE you transfer that data. And again, the reason is simple - during a up-load process to SharePoint, autonumbers WILL CHANGE!!! And since they change, then any other dependent table that uses those PK values (as a FK) MUST have been part of a defined relationship. If they are not defined before migration to SharePoint, then a change in a PK value will NOT tell SharePoint to go and find and correctly update all of the "child" records or so called FK values.
So, the first question to ask is did this break in related numbers occur a long time ago (at migration time), or did this break occur due to some bad code, or the wrong values having been selected?
So, migration of related data to SharePoint is a "delicate" operation, and the main reason of course is that the related tables MUCH have been setup as enforced relationships BEFORE you migrate. If such relationships were not strict defined, then during the migration process then the relation of data based on those PK/FK values will break at that migration time.
Now, it could be a simple issue that this sub form in question does not have the correct link master/child settings - that's the first thing to check.

How to save row values from one field in subform to main form record? - Access

I have a parent form (frmGroupSession) that has a subform (SubFormParticipants) in datasheet view. The subform is based off a query that selects all participants ([CLIENT ID], [NAME], [ATTENDED]) that had attended a specific group [GroupID] on a specific date [GroupSessionDate]. The parent form saves to a table that logs group sessions (tblGroupSessionLog). I need to save the group's participants [CLIENT ID] to the record within tblGroupSessionLog
Basically, I need to pass data from the subform to the record within tblGroupSessionLog. I'm not sure what the most effective way to do this, if it's possible at all. Ideally, I would like to have each unique participant [CLIENT ID] stored in its own field within tblGroupSessionLog. If there were 20 participants in the subform then each row value from the first column/field [CLIENT ID] would be passed to the corresponding field within tblGroupSessionLog ([ClientID1] thru [ClientID20])
I am relatively new at this. Even asking the question was difficult.
I am not sure what else I can provide to help you wizards with the solve, but let me know and I will.
Thoughts? Ideas?
Access 101 : You have a many to many relationship You should look that term up but in short it means clients can belong to many groups and each group can have many clients. (so bang your data into a normalized structure similar to the following:
First tip make sure to add the relationships under database tools (you should look that up). Access needs to know how the tables are related to manage the keys behind the scenes and sometimes access makes better decisions about automatic form creating when it already knows the relationship structure. Once your data is properly structured access makes it easy to produce functional if much less than styling data entry forms which can also be used as even worse search forms. For instance Click on any table and hit create form on the ribbon and access will create the data entry form form you.
Basic Style tip 1: Always delete primary key fields like ClientID from the form. The field is still there in the form's record source being managed by access. Users almost never need to see any table keys. This gives you a basic data entry form which you can also use to scroll through any clients you have entered using the record selector circled at the bottom of the frmClients.
Play around with the record selector to see how it works. In particular go past the last record and you will find you can enter new clients and access will automatically give them a ClientID. You can also cycle through your Clients and update them using this form it just isn't stylish. In the same way we can make a form for the groups table.
You make a form for the frmGroupSessions table in the same manner as the others but add a step. Replace the text boxes holding ClientID and GroupID with human readable comboboxes. Here is a link to help with that: https://www.google.com/search?q=access+change+text+box+to+combo+box&oq=access+change+text+&aqs=chrome.0.0i457j0l2j69i57j0j0i22i30l2.7503j0j1&sourceid=chrome&ie=UTF-8#kpvalbx=_r0sFYJ7vBcfY5gLz2aTgBw15
Becomes:
At this point play around to learn. Use the Record Selector at the bottom of frmGroupSessions to add and modify data. Play with the Tables and see what happens. Start messing with the form properties in particular the default view. Soon you will have ideas about how the form could be better and you can start figuring out how to style them.

Access Linked Tables, how to force relational values

Hopefully the image above makes it thru. So the way this works is that a user uses a form to enter the values on the Vuln_Remediation_Planning table. After all vulnerabilities associated with a patchID and existing OS have been entered, he moves to the next form where he is suppose to mitigate the risk associated with the vulnerabilities, and you can have multiple mitigating measures which is why the table is separate.
My question:
Right now when using the compensation form, the user has to select each patchID, OS, and vulnerability ID for each mitigating measure they select... this is cumbersome and error prone. Recall the first form only operates on the planning table, the second form operates on the compensation table.. but they are related so I feel the user would want to use a single drop down to select the top the primary keys, already assign in the previous table.
I was going to ask how to handle this, but I may have solved my own problem... 3 column combo box right, with the row source coming from the Remediation planning.... lol what do you think, any other ideas?
I figured it out. On the compensation table I just created a continuous form, and moved the OS and patchID fields to the header. When opening the form normally, it looks funny because the header values change when records are selected (as would be expected if they were all on the same row). Then from the remediation planning form, I have a button to open the compensating measures form that filters it so only the patchID/OS of the parent for is shown. Additionally, in the open event of the compensating measures form, I set the default values of PATCHID/OS using open args (in case no records are there yet or the user adds new records... otherwise it opens blank when there are no records.

Editing table row data populated with with classic asp

I'm hoping this will be a rather simple question to answer, as I'm not looking for any specific code. I have a table on a classic asp page populated from an sql server. I've just set the table up so that each row is clickable and takes you to a page to edit the data in the row. My question is this: Would I be better off trying to use the recordset that populated the table or should I reconnect to the db and pull just the record I want edited.
As always; It Depends. It depends on what you need to edit about the record. It depends on How far apart your DB and site are from each other. It depends on which machine, if the DB and site are on separate machines, is more powerful.
That being said, you should make a new call for that specific record. The reason mainly being because of a specification you made in your question:
...and takes you to a page to edit the data in the row
You should not try to pass a record set between pages. There are a few reasons for this
Only collect what you need
Make sure data is fresh
Consider how your program will scale
On point 1 there are two ways to look at this. One is that you are trying to pass the entire record set across a page when you only need 1 record. There are few situations where another DB call would cost more than this. The other is you are only passing one record which would make me question your design. Why does this record set have every item related to a record. You are selecting way too much for just a result list. Or if the record is that small then Why do you need the new page. Why can you not just reveal an edit template for the item if it is that minimal.
On point 2 consider the following scenario. You are discussing with a coworker how you need to change a customer's record. You pull up this result set in an application but then nature calls and you step away from you desk. The coworker gets called by the customer and asked why the record is not updated yet. To placate the customer your coworker makes the changes. Now you are using an old record set and may overwrite additional changes your coworker made while you were away. This all happens because you never update the record set, you always just pass the old one from page to page.
On point 3 we can look back a point 1 a bit. let us say that you are passing 5 fields now. You decide though that you need a comments field to attach to one of your existing fields. do you intend to pass 2000 characters of that comment field to the next page? How about if each of the 5 need a comment field? Do you intend to pass 10,000 characters for a properly paged record set of 10? do you not do record set paging and need to pass 10,000 characters for a full 126 records.
There are more reasons too. Will you be able to keep your records secure passing them this way? Will this effect your user's experience because they have a crummy computer and cannot build that quick of a post request quickly? Generally it is better to only keep what you need and in most situations your result set should not have everything you need to edit.

Webmatrix - Conditional database changes?

So i have an issue, where that properties on my website are either active or inactive. A property is deemed as inactive by default, and i want it to only become active once it has met some criteria. For example, i only want it to become active when a description is provided, at least one rate has been applied, and only when it has a valid ZIP code assigned.
How would i achieve this, since a user might not populate all this information upon first registration, and may want to come back at a later date to finish updating before it becomes active.
The only way i can think of, is to run an "if" statement, each time i update information on a property, which i can work with, but i was wondering if there was any other conditional way of making this happen, where the database regularly checks to see if should set something to active?
Thanks, Gavin
If you were running a full version of SQL Server, you could accomplish this with a trigger and a bitflag column like VoidKing suggested. On the save the trigger would trigger and you would write a complex sql statement that test if all the needed fields are filled and set the bitflag to true or false depending.
I did something like this in a simpler way by having two save buttons. A "save" that didn't trigger any validation and a "Save and Release" button that applied validation to all the needed fields. Both buttons saved the data, but the save and release button would only save if the validation passed and it would save the bitfield "isActive" to 1 where the other save method would save it as a 0.
Might be a good approach else you are left with your checking logic on the single save button, which isn't a bad way to go either.