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.
Related
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.
I want my web application to continue from where it left off or to continue with its old session irrespective of the browser in which it is opened.
Main Technologies used for my application are java, spring, Hibernate and angular5.
I have done some research and it suggests me to use cookies to save session data.
Is using cookies the only way i can achieve it or is there a better way to do it?
Thank you in Advance
If you want to have session data across multiple browsers (irrespective of the browser in which it is opened), a cookie and localStorage won't help you, since those are only related to one browser instance.
What you need would be to store all the data, that you want to have in your session, in your database in an appropriate data model, and then every time a user logs in, you fetch that data and add it to the current server session. Of course you also have to update the data if there are any updates.
E.g. for a shopping cart, like in Amazon, which is stored in your account and not in the cookie or browser, you would have a table ShoppingCart with a relation to the customer id, and then CartItems with a foreign key to the cart, and you would fetch the shopping cart for the customer which is currently logged in, to show all the items.
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.
I'm using the EclipseLink provider to talk to a mysql database. I've noticed that in on area of my application the library is returning query data that doesn't match the DB.
The query is:
#NamedQuery(name = "EmailAddress.findAll", query = "SELECT e FROM EmailAddress e")
This query is correct, I'm certain of that. The code that I'm using to run that query is:
EntityTransaction entr = em.getTransaction();
entr.begin();
emailAddresses = em.createNamedQuery("EmailAddress.findAll").getResultList();
em.close()
I've put a breakpoint on the close so that I can see the contents of the emailAddress list, about 1 time in 3 it the array is populated incorrectly.
A bit more background - I have a table that lists names, clicking on a name pops up a dialogue and allows you to change the name, upon clicking save it closes the dialogue and updates the table (both DB and UI), sometimes the UI is incorrectly updated and the editted name does not update. The update runs code including that above block. The database is correctly updated prior to the code being run, it's just that array is not populated correctly.
Has anybody else had any issues related to this or have any ideas?
Any help much appreciated!
I fixed this by making the cache refresh on every query, so it was something with the cache. As this app is single user and not very big there aren't many DB hits so this is fine for this application.
Difficult to say without seeing the rest of the code, but are you sure that:
Your transactions are not long winded (i.e. you don't open a transaction and keep it open while waiting for the user is doing something). You should open and close transactions around data queries/updates only.
You are calling persist(), merge() and refresh() respectively when you are creating or updating entities.
I got similar domain model
1) User. Every user got many cities. #OneToMany(targetEntity=adv.domain.City.class...)
2) City. Every city got many districts #OneToMany(targetEntity=adv.domain.Distinct.class)
3) Distintc
My goal is to delete distinct when user press delete button in browser. After that controller get id of distinct and pass it to bussiness layer. Where method DistinctService.deleteDistinct(Long distinctId) should delegate deliting to
DAO layer.
So my question is where to put security restrictions and what is the best way to accomplish it. I want to be sure that i delete distinct of the real user, that is the real owner of city, and city is the real owner of distinct.
So nobody exept the owner can't delete ditinct using simple url like localhost/deleteDistinct/5.
I can get user from httpSession in my controller and pass it to bussiness layer.
After that i can get all cities of this user and itrate over them to be sure, that of the citie.id == distinct.city_id and then delete distinct.
But it's rather ridiculous in my opinion.
Also i can write sql query like this ...
delete from
t_distinct
where
t_distinct.city_id in (
select
t_city.id
from
t_city
left join t_user on t_user.id = t_city.owner_id
where
t_user.id = ?
)
and t_distinct.id = ?
So what is the best practice to add restrictions like this.
I'm using Hibernate, Spring, Spring MVC by the way..
Thank you
What you're asking for is not SQL Injection prevention. You need to ensure the user attempting the deletion is authorized.
As long as you check that the user accessing the page has the rights to delete the row your trying to delete (this would be checked in the Business layer), and ONLY allow the delete command if the user is authenticated and authorized to perform the action.
With hibernate you don't have to worry about sql injection. It always uses prepared statements, so you are safe.
As for your concrete case, this is not an sql injection. But to prevent it, make validation in the controller - whether the currently logged user owns the desired ID.
Depending on the size of the application, you can implement some general security scheme, with ownership settings, and apply it (using AOP).
I understand that i want to be sure, the the user is real owner of Book The question was how to accomplish it. And yes, i know that user is authenticated and authorized. But another authorized user can easy delete pages of another user.
This can be done like this...
User userFromHttpSession ...
Long bookId = load page, get bookId, load book, get bookId
List books = userFromHttpSession.getBooks();
... iterate over books and find out if one of the book.id == bookId
... then if book owner is owner of httpSession, then proceed Delete
It's like too many sql queries, and too many code, probably there are better solution. Anyway thank you for your answers
Just use your head, quote-escape* everything from an outside (or inside for that matter) source before it gets put in an SQL statement, and check data as it goes in. Or, use prepared statements.
*Edit: By "quote-escape" I meant functions like PHP's mysql_escape_string()