Object getting wrong time stamp from Hibernate saved to database - java

I am new to Hibernate and working on a web project that uses it.
I have an object called area that has a date object(java.sql.Timestamp) attribute modifiedDate. When I create a new object modifieDate is null and after send it down to getHibernateTemplate().saveOrUpdate(area); in my own class that extends org.springframework.orm.hibernate3.support.HibernateDaoSupport it is set with current timestamp and saved in the database. In the database it is saved as a datetime.
My problem is most of the time the object is updated with a Date that is 1 millisecond off compared to what it is saved as in the database, this leads to this exception
if anything is attempted updated without reloading the page:
an org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
There are no problems with the correct date when getting the object from database subsequent, it is only at creation it gets the wrong value.
Is there a way to get the correct modifiedDate at SaveOrUpdate?
Incase it is needed the mapping uses <timestamp name="modifiedDate" column="ModifiedDate"/> and all test are run on localhost with everything running on the same machine.
I already have a work around, by calling getHibernateTemplate().refresh(area); right after the saveOrUpdate I get the right timestamp, but I would still like to know if there is a way to get the correct modifiedDate at saveOrUpdate.

My theory:
What's happening is that you're using a less precise data type on the database side than on the Java side, so the values you persist to the DB are losing precision (or rounded somehow, see below) during generation of the DB-specific SQL. Here's how to tell for sure:
Remember, Hibernate works by generating SQL statements that are executed in your database. In order to diagnose issues with Hibernate mappings like this, you will need to see the SQL being executed in order to know precisely what's going on.
Turn on the 'show SQL' setting for Hibernate. This will cause Hibernate to dump the raw SQL being executed on the database.
Examine the logs from your tests. It will help to implement toString on your class and log the value to compare against the SQL hibernate generates for an INSERT. Do the values in the SQL statements match the value of the Java timestamp field?
You should check the precision settings for your database's DATETIME type. For example, on SQL Server, DATETIME implements millisecond rounding (see 'accuracy' field) that effectively causes loss of precision for millisecond values. You will want to change the Java type your column is mapped to or change the type of the column in the database, depending on your precision needs.

Related

Bypass Jooq optimstic locking and DefaultRecordListener for some method

I would like to synchronize table from server A to B, the record should be exactly same from the source. It is just like manual replication work.
The method is retrieving from source record as json and insert/update to destination server to get same table records including version field.
I have a problem with updating from source to destination, I found no matter how the each fields are identical, it will update date modified and version field.
Any solution to force update those fields(version or date) without turn off optimistic locking parameter and bypass customized "DefaultRecordListener" class
As of jOOQ 3.11, it is not possible to bypass setting of record version or timestamp with an out of the box feature. I have created a feature request to implement this in jOOQ 3.12: https://github.com/jOOQ/jOOQ/issues/8924
There are a few workarounds, all of which assume that you've already turned off Settings.executeWithOptimisticLocking in your data copying logic
Workaround: Using a RecordListener
If you're using record versions (not timestamps), you could set the record version to version - 1 prior to storing your record. That would lead to the version being updated again to the same value. A hack, but might be good enough.
Workaround: Re-generate tables for this purpose
You could re-generate all the tables involved in this operation a second time without record versions / timestamps, and use those alternative generated tables for your data copying.
Workaround: Don't use UpdatableRecord
Instead of using UpdatableRecord, you could write actual INSERT statements. Notice that you can pass any Record to an INSERT statement via the InsertSetStep.set(Record) method. It will have a similar effect as calling record.insert(), i.e. only the changed fields will be inserted.

How to store date as Oracle SYSDATE with JpaRepository save method?

I am working on a Spring Data JPA project, where I want to store Oracle SYSDATE in a date field of a table. I can not modify the table at all.
Right now, what I am doing is passing new Date() to that date field. Which is not correct as the Oracle server is in a different timezone.
I am not writing any query to insert the data, instead I am using JpaRepository save() method.
How can I do this?
P.S. I do not want to hard code the timezone of the database server in my code.
There is no direct way to do this (see Setting default values for columns in JPA).
What you could do is to perform a select SYSDATE from dual and use the result to set your property.
The method to get the sysdate could be in your Spring Data Repository
#Query(value=`select SYSDATE from dual`, nativeQuery=true)
Date currentDate();
You could set the value in a #PrePersist Listener (see onSave() (for any Entity saved with Hibernate/Spring Data Repositories) ).
But I think you can't perform queries in those listeners, so the next thing would be to create a custom implementation of Spring Data's save method, so that it gets such a value and keeps it available for the Listener, before actually saving anything. Alternatively one could use a separate connection of the query.
Obviously, this all adds another database roundtrip, which is rather expensive.
An alternative would be to get the current time of the server once and use that just to determine the correct offset to use and create the timestamps locally, using that offset. This is much faster and easier but breaks when application server and database server have different daylight saving time rules.

How to ensure date is stored from Java to SQLServer to millisecond resolution?

We are using Hibernate.
In Java, the object is java.util.Date.
In SQLServer, the column is datetime2(7).
When we store this object in SQLServer database and later retrieve it, this object is not having same value in millisecond resolution.
For example, from Java: Dec 01 2016 15:50.453
When it comes back from the database: Dec 01 2016 15:50.455
So, we are encountering scenarios where the equals() is failing due to this design aspect of SQLServer.
Is there something missing in Hibernate dialect, like for example: registering column types.
Or should I define some conversion, so that I get the correct value, which I had saved.
That's a bad design. You can't guarantee any such thing.
Instead of creating a value on the Java side and passing it to SQL Server, why not call CURRENT_TIMESTAMP on the database server and save that?
It's not clear to me from your description where the timestamp lives on the Java side. Is it in the Java object itself? Is that the value that you INSERT into the database? You're saying that the value from the object is off two 2 milliseconds when you persist it in SQL Server?
I would suggest that your design would be better off not depending on timestamps being accurate to a millisecond.
I'll point out that you have no hope whatsoever of changing any design aspect of SQL Server or Java.
Perhaps it'd be easier to answer if you could post more requirements that would clarify why you depend on the timestamp.

Converting date as timestamp while selecting using Hibernate APIs

We have a GUI application which sends around 40 parameters to the DB.
Based on these parameters a dynamic query is generated to fetch data. Number of fields that needs to be selected remains the same, only where condition differs.
Hibernate criteria API is used to form dynamic queries. We are using SQLMX as the database running on HP Nonstop server.
Certain dates need to be stored as 0001-01-01. Now, while selecting this field (DATE datatype), application displays this as 2001-01-01. When query is run from RazorSQL also, we are seeing incorrect results.
I could resolve this issue in RazorSQL by doing "select (cast(date1 as timestamp) from table". This gives date correctly, but with timestamp. This is OK.
In Java application, I suggested project team to use NamedNativeQueries wherein CAST as TIMESTAMP construct is specified in the query itself. Later on , I came to know that team cannot used NamedNativeQueries since queries are dynamic in nature. (Where condition can have 1 or 5 or no clauses).
Tried using Temporal.DATE annotation. Did not work. What i observed is that, we need to cast the date to timestamp while selecting itself. setMethod for the variable gets called after query has happened and if we do not do cast while doing select, value of 0001-01-01 gets changed to 2001-01-01.
Is there any way we can apply SQL constructs (similar to_date in Oracle ) before the query is executed?

Using a criteria for time restriction

I'm having some problems with a simple query I'm doing.
I have a postgresql database, with a time wihout zone column.
I cannot change the type of this column. Also, I have to use criterias, so don't tell me to change this. However, if there is a better solution for the future instead of using the time type I'm curious about it.
This column is mapped to a java.util.Date attribute. This could be changed to Time or whatever.
What I'm doing is adding this :
Time someTime = someDate.getTime();
criteria.add(Restrictions.eq(propertyName, someTime)));
This criteria doesn't return anything, when it should. What is done is the following: The user puts some string time, that is parsed to Date, being that 1970-1-1 and the time. This time is then added to the criteria. Also, the time in the database I'm using as example, is the same Date (1970-1-1, etc) that the one that is created when parsing the user data.
I have tried to search for some documentation on how criterias are used against time without timezone but haven't found anything.
Suggestions why this is failing?
UPDATE:The problem has been solved using the library JodaTime. But I still don't understand why was failing...

Categories

Resources