Friday, May 13, 2016

It's hibernation time

This one is in English only, as code and Hebrew text don't mix well. 
The information below isn't new, and can be easily found in the internet, but after being burnt by it three times, perhaps it's time I put a warning here for everyone else to see, and for me to remember. 
Some of us are working with Java. Or are testing code developed in Java. In this case, I think it's safe to assume that most are working with a database, and some of them will be using Hibernate, or any other ORM library. If you are in this situation, check your wristwatch often. 
More specifically, check that every time you store in the database any indication of "when" it contains both the right date and the correct time.Sometimes, one of them will be set unintentionally to the default value (either Jan 1st 1970, or midnight - depending on the part that got messed up).  
I encountered this in a hibernate implementation, but some of the answers here claim that this issue is at the JDBC layer, so it might exist in any Java database operation (When we were using plain JDBC, or JDBC template, we accidentally avoided this by writing it as a string, but it might happen also there). 
Now, let's have a look at the problem itself: 
Those of you working with Java probably already know that it has a really crappy approach to dealing with time. You have at least two objects named "Date" (java.util.Date and java.sql.Date, which inherits from the first), then you have java.sql.Time and java.sql.Timestamp. I'm leaving outside the proper approach to dealing with time through Calendar objects, since when working with databases you will eventually have to use java.util.Date, or any of its sub-classes (all of the mentioned above are directly extending it). 
Why so many classes you ask? that's a good question. The reason is probably that SQL has a conceptual separation between date & time. "Date" is a representation of the year-month-day, where "time" is the hours-minutes-seconds-milliseconds part. So, java.sql.Date and java.sql.Time are mimicking this logic, with java.sql.timestamp filling in for SQL concept of Timestamp (which is simply date+time). 
Now, let's have a look on a pretty standard hibernate mapping of a table.
The table is defined:

Which looks in Java like this:

If your DB column is defined as date (which, at least in Oracle's DB is accepting also hours and minutes by default) most Hibernate code generators (you didn't think someone was actually going to manually map those DB columns to Java, did you?) will use by default TemporalType.DATE which, in turn, will cause your application to save dates that are only exactly at midnight. 
Or, even if you fixed your annotations properly, the setter is still getting a java.util.Date, you can have one of your developers (including yourself) put a line such as: 
And now you'll have a perfectly good Jan 1st 1970, but with the correct hour.


So, If you are working in these conditions (Java, some ORM, and probably with Oracle too) - take special care to check that the time & date are written properly to each an every column, and recheck it whenever you upgrade your JDBC driver or your ORM version as well.

No comments:

Post a Comment