I am getting a duplicate key error from the database (MySQL) for the scenario I have explained below.
Background
I need to save an entity to my database, but the entity id is not managed/generated by my system, so it comes from 3rd party with an id and I need to save it with its id. When our application does not manage its id, Spring Data(R2DBC) cannot know if it is a new entity or not because there will be an id on it all the time. According to their documentation, there are several ways to tell Spring if it is a new entity or not, so I have chosen to implement a Persistable entity so that I can tell Spring if it is a new entity. However, I need to query DB to understand if it exists or not. Please note that I am using Spring reactive so putting a synchronized keyword is not a solution for me...
Here is the problem
Imagine that 2 requests come almost at a time. For the second request, it will query the DB and get nothing since the first request has not been saved yet. It will decide to create the second request, but at that point, the first request is committed to DB, and as a result, the second request will get a duplicate key error since I told Spring that it is a new one.
I have been thinking of solutions to solve this problem but I couldn't find any yet... I would really appreciate it if you could help me on this matter.
Thank you in advance!
You're gonna have the same problem with pretty much any entity system. Let me explain: Let's say we have a register endpoint. Two people register at the exact same time using the exact same email address. Then both are gonna be saved to the database since R2DBC does the same flow taking the exact same time for both requests.
The simplest solution for this problem is not checking the email at all and just accepting that you're not gonna deal with it with your own code. Instead you can change the database schema for your table. I don't know how you create your table but I just use a sql file with the code for it inside. In my case by making the email column UNIQUE we can prevent this problem in the database instead of preventing it using our own logic. My schema file for the accounts table looks like this:
create table if not exists accounts (id SERIAL NOT NULL, username VARCHAR(32), rank VARCHAR(32), email VARCHAR(32) UNIQUE, password VARCHAR(512), invitor INT, data TEXT, PRIMARY KEY (id));
You can also check out the w3schools article about the UNIQUE constraint.
Related
This question already has answers here:
SQL Server Insert if not exists
(13 answers)
Closed 8 years ago.
I have a table users with primary key column email.
I have a piece of code where I store the user that simply invokes userDao.store(user);
Since the constraint exists, I can catch the exception and show the error on the UI. This approach works fine.
Another solution is to check first if the user exists and then store him in the database. This would result in two consecutive queries - select and then insert. So basically if the user exists I show the error. The issue I see here that if two users with the same email try to register at the same time and provide the same email. It may happen than both threads check the existence of the user and return nothing. Then the first thread saves the user and the second throws exception.
The third approach is to use MERGE query (I use hsqldb). Basically in one query I insert the user only if he does not exist. Then I can see the result of the query. If no rows have changed then it means that the user exists and I can show the error. Either of these approaches would not violate the consistency of my data. But I am looking for the best practices on how to handle this kind of problem.
Your first instinct was correct. To protect against duplicates, define a UNIQUE constraint on that column. Then catch any exception resulting from a violation of that constraint.
SQL lacks an atomic insert-if-not-exists command. You will see code using a nested SELECT statement, but such code is not atomic, so you would still need to trap for the UNIQUE constraint violations.
This Question is basically a duplicate. Search StackOverflow for more discussion and examples.
By the way, I would recommend against using email address as a primary key. If a user wants to change their email address on their account, you will have to update all related records using that value as a Foreign Key. I suggest using a Surrogate Key instead of a Natural Key almost always.
The chance of that happening is so remote you really don't have to consider it. Especially if you use email validation before someone can use the system. If you still are worried you can minimize the chance by using a synchronize operation on the call that checks for the existence of the email. The only way this would not work is if you have a clustered environment with the code running on 2 or more load balanced servers.
For persisting data used hibernate with SQLServer. In system every table contains four column.
1. Created User
2. Created Date
3. Modified User
4. Modified Date
From beginning system does not contain any mechanism for entering "modified User" and "modified Date" while insert and update operation.
My Question. is there any way in hibernate to entering modified User and Modified Date without changing every where ?
My question:
1)Is there any way to provide user(inform of Id or bean) to hibernate ?
2)If Yes,How can I tell to hibernate that populate this two columns while doing insert of records?
Thanks for any help.
One way would be to change of your servlets, or rest controllers, or possibly DAO's you are writing.
A second way is to create a DAO, servlet, or rest controller that gets the user object and date and make all of your servlets/daos/controllers extend the one you just made.
It is a pain in the behind but it would be better than setting a single point of context.
Passing security context(user) and date to a DAO is pretty easy to do and would be a lot easier to maintain in the future.
I'm using Spring Roo, and Spring MVC.
I have Set up Spring Security to use a MySQL database and auth using the standard schema, table users, table authority.
What I have is a webapp to take orders from our sales people in the field. Simply they just fill in the form and submit it to the database.
The ROO generated MVC pages are fine to start, but I need to make some changes and I'm not sure exactly how to do it. I'm just getting my feet wet learning java.
What I need is for our sales order form to capture the username, and the submitted record would be tagged with their username, and then filter the view so that the sales person can only see the records that they themselves have submitted.
Also I would like to implement a stylus signature capture at the bottom of the form. I tried to figure out how to use http://thomasjbradley.ca/lab/signature-pad/#howto but I'm getting lost on where to put the code. I assume in src\main\views\salesorders\create.jspx
I understand this part is off-topic to my original post.
You will need a table in your database that holds the order forms. An important part of this table will be each row will need to contain a way to map back to the user that submitted it. This will most likely be easiest to implement with a column that is a foreign key to the user table.
When it comes time to fetch for forms for a specific user, you will need to query the order forms table and use a WHERE clause that restricts the rows to just the current user.
As for your second question, it will likely be more worthwhile for you to ask in another question on stackoverflow, as it doesn't really pertain to the original question at all.
Is it a bad practice to expose DB internal IDs in URLs?
For example, suppose I have a users table with some IDs (primary key) for each row. Would exposing the URL myapp.com/accountInfo.html?userId=5, where 5 is an actual primary key, be considered a "bad thing" and why?
Also assume that we properly defend against SQL injections.
I am mostly interested in answers related to the Java web technology stack (hence the java tag), but general answers will also be very helpful.
Thanks.
That bases on the way you parse the URL. If you allow blind SQL injections that is bad. You have to only to validate the id from the user input.
Stackexchange also puts the id of the row into the URL as you can see in your address bar. The trick is to parse the part and get did of all possible SQL. The simples way is to check that the id is a number.
It isn't a bad thing to pass through in the URL, as it doesn't mean much to the end user - its only bad if you rely on that value in the running of your application. For example, you don't want the user to notice that userId=5 and change it to userID=10 to display the account of another person.
It would be much safer to store this information in a session on the server. For example, when the user logs in, their userID value is stored in the session on the server, and you use this value whenever you query the database. If you do it this way, there usually wouldn't be any need to pass through the userID in the URL, however it wouldn't hurt because it isn't used by your DB-querying code.
To use the database ID in URLs is good, because this ID should never change in an objects (db rows) life. Thus the URL is durable - the most important aspect of an URL. See also Cool URIs don't change.
Yes it is a bad thing. You are exposing implementation detail. How bad? That depends. It forces you to do unneeded checks of the user input. If other applications start depending on it, you are no longer free to change the database scheme.
PKs are meant for the system.
To the user, it may represent a different meaning:
For e.g.
Let's consider following links. Using primary-key,it displays an item under products productA, productB,productC;
(A)http://blahblahsite.com/browse/productA/111 (pkey)
(B)http://blahblahsite.com/browse/productB/112 (pkey)
(C)http://blahblahsite.com/browse/productC/113 (pkey)
User on link B may feel there are 112 items under ProductB, which is misleading.
Also it will cause problem while merging tables since PK will be auto-incremented.
I am using Hibernate in Spring MVC 3.05 and an Oracle database.
I have a transaction in which I insert a new record into two tables: User and Registration.
Registration contains a UserId (meaning a user may have many registrations).
When I commit the transaction, I can query my database and see that the new rows were successfully inserted.
The problem
After the transaction commits successfully, I redirect the user to a confirmation page, where I would like to show some information about the registration that was just inserted. On the confirmation page, I do a Hibernate query by userId to get the User that was just inserted. I then use the following properties to populate my model:
User.getName()
User.getEmail()
User.getBlah()
User.getReigstrations().iterator.next()
The one in bold throws an exception "NoSuchElementException" because there are no items in the set. There should be one Registration in the set. If I close the browser, start a new one, and direct myself back to the same link that threw the exception, IT WORKS! There is a Registration in the set.
My guess is that it's not reloading related table objects when I query for my User, but is either pulling from cache or assuming that nothing more had been added since the User was saved. Does anyone know of a way to force Hibernate to reload this data?
Unfortunately I can't just get a Registration by UserId because it maps UserId to the entire User object (via object generation because User is a foreign key).
Hope this makes sense. Any help is appreciated. I am open to a different approach to accomplishing this as well. Thanks!
It's hard to diagnose the exact problem because you don't say when you close sessions, and in which session/transaction you get your User. But I guess the problem comes from the fact that you don't maintain the two sides of the relationship when inserting a new registration.
You should set the user in the registration, and add the registration to the list of registrations of the user.