hibernate TemporalType ,datetime column mapping - mysql

i have column type is datetime in mysql
and i use hibernate
#Temporal(TemporalType.TIMESTAMP)
private java.sql.Timestamp lastExpressTime;
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date lastExpressTime;
#Temporal(TemporalType.DATE)
private java.sql.Date lastExpressTime;
are there some difference between those?
datetime should mapping what kind of TemporalType?
i find a reference Table 5.2 MySQL Types to Java Types for ResultSet.getObject()
datetime should mapping timestamp?
thanks for your any help and suggestion in advance

With TemporalType.TIMESTAMP, when you persist/read lastExpressTime to/from database, both date and time will be persisted/read.
With TemporalType.DATE, when you persist/read lastExpressTime to/from database, only date will be persisted/read and time part of the date will be set to all zeroes.
Not sure if this behavior is the same for all databases, best would be to check this in your own test.

Related

Timezone issue in Spring Boot JPA application

I am facing date time issue in my spring boot jpa application.
For example, In my database I have one column created_on which contains 2019-07-11 09:30:00 date.
When I fetch this record threw JPA it converts to UTC.
Means date 2019-07-11 09:30:00 converts to 2019-07-11 05:00:00.
My System time is in IST and date is saved in database in IST as well.
I am using mysql database.
In my Enitity
private Date createdOn;
Database column:
created_on timestamp
Service:
#Service
#Transactional(readOnly = true)
public class EntityTypeService {
#Autowired
private IEntityTypeRepository entityTypeRepository;
public EntityType findById(Long id) {
EntityType entityType = entityTypeRepository.findById(id).orElse(new EntityType());
System.out.println(entityType.getCreatedOn());
return entityType;
}
}
Repository
#Repository
public interface IEntityTypeRepository extends CrudRepository<EntityType, Long> {
}
Date in database is 2019-07-11 09:30:00
But when I print it on service System.out.println(entityType.getCreatedOn()); it gives me 2019-07-11 05:00:00.
This is generic issue in my whole application.
After so much research I found the solution.
Actually issue was because of
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
this property which I have set in my appication.properties.
When I removed this property everything works fine at the backend. Backend showing the perfect time which is available in database.
But now when response comes to frontend, at that time my date gets converted to UTC.
Like backend it's showing 2020-06-03 18:56:14.0 and when it comes to front end it converts to 2020-06-02T13:26:14.000+0000.
Which is also an issue for me.
So after some more research I found that Jackson by default converts all date to UTC when object send to frontend.
The solution to this problem is
spring.jackson.time-zone=IST
My Database and System timezone is IST so I have set IST to jackson timezone too which solves the problem.
Hope this answer may help someone.
You can set timezone for in database connection using serverTimezone eg:Asia/Kolkata and use useLegacyDatetimeCode=false
spring.datasource.url= = jdbc:mysql://127.0.0.1/db_name?useLegacyDatetimeCode=false&serverTimezone=Asia/Kolkata
And don't use legacy class Date rather use modern class LocalDateTime
When working on JPA + Spring Boot for a backend application, make sure to use same TimeZone through out server configuration. For example, to use UTC do as below:
On server OS level: sudo timedatectl set-timezone UTC (for example on Cent OS)
On MySQL / Database server in my.cnf file (optional)
Spring config: spring.jpa.properties.hibernate.jdbc.time_zone=UTC
MySQL URL query parameters spring.datasource.url=jdbc\:mysql\://localhost\:3306/my_db_name?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useLegacyDatetimeCode=false
And if you are using Jackson JSON framework you can automatically parse DateTime value to String format using #JsonFormat(shape= JsonFormat.Shape.STRING, pattern="dd MMM yyyy HH:mm:ss") on the entity property / field.
Application entry point #SpringBootApplication
#PostConstruct public void init(){ TimeZone.setDefault(TimeZone.getTimeZone("UTC")); }
This should cover most of the implementation challenges while work on Dates and Timestamps. Hope that it helps.
Try to avoid using Date for timestamps in time zones because it is not designed to handle these in a good way.
You could try to print the date object with a formatter or use LocalDateTime (or ZonedDateTime if time zones are important to you) instead.
You may try putting #DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") on createdOn setter.

Hibernate store YearMonth in MySQL as Blob instead of text

A Spring Boot 2.3.0 Project is Storing Data in MySQL 8.0. (jdk 9)
A JPA Class has Java 8 YearMonth field
#Data
#Entity
public class Version {
...
private YearMonth releaseDate;
private LocalDateTime createdAt;
When I persist an instance of version, it's stored like this:
As You can see LocalDateTime gets stored as text but YearMonth as Blob. Now When I get back the entity it works fine and I do get YearMonth value.
The problem is that I cannot read it through MySQL Workbench. And I know that EclipseLink (official implementation of JPA) does persist YearMonth as Text.
How Can I store it as Text and not BLOB?

JPA mapping failing on strange message

I have a strange problem where the JPA mapping is failing on converting to a timestamp, but the value it's using appears to be the entire row, not just one variable.
The error is:
java.sql.SQLException: Value '1988├╗ ├╗├╗├╗├╗├╗├╗0
07 1234567 wk├╗0├╗├╗├╗├╗├╗ ' can not be represented as java.sql.Timestamp
where the value seems to be the entire row, with most of the bad characters being nulls. Debug logging isn't giving me much at the moment, and I'm not sure whether it's an error in my mapping class, collation issues, or something else.
MySQL workbench reads all the information from the table correctly. Running mysql from the command outputs all the data correctly. Neither show any special characters anywhere.
A simplified version of my mapping class is:
#Entity
#Audited
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class PersonSundry {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="person_id", unique=true)
private Person person;
#ManyToOne(fetch=FetchType.EAGER)
private Lookup1 lookup1;
#ManyToOne(fetch=FetchType.EAGER)
private Lookup2 lookup2;
#Lob
private String backgroundInfo;
private LocalDate dateOfSomething1;
private LocalDate dateOfSomething2;
private LocalDate dateOfSomething3;
// getters and setters
}
Has anyone come across this before? Any ideas where else to look?
EDIT: The root cause turned out to be a generic failed cast of 00-00-0000 to a timestamp, however I'm going to leave the question open to see if someone knows where the strange error message was given instead of an exact one.
Are you using MYSQL?
Please try using this type of connection string.
jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull
Datetimes with all-zero components (0000-00-00 ...) — These values can not be represented reliably in Java. Connector/J 3.0.x always converted them to NULL when being read from a ResultSet.
Connector/J 3.1 throws an exception by default when these values are encountered as this is the most correct behavior according to the JDBC and SQL standards. This behavior can be modified using the zeroDateTimeBehavior configuration property. The allowable values are:
exception (the default), which throws an SQLException with an SQLState of S1009.
convertToNull, which returns NULL instead of the date.
round, which rounds the date to the nearest closest value which is 0001-01-01.

Storing milliseconds in MySQL timestamp column using Hibernate

I'm trying to store a java Date with milliseconds in MySQL's timestamp column using Hibernate, but the millisecods are stored always as .000.
The definition of the column in hibernate is as follows:
#Type(type="timestamp")``
private Timestamp timestamp;
In DB the column is declared as TIMESTAMP(3)
I've tried different combinations, including Date, but neither helped.
I use MySQL 5.6.25, Connector/J version 5.1.37, Hibernate 4.0.1.
I've been investigating it for a while, but still couldn't find any solution that works form me.
ANy help will be appreciated.
Have you tried using DATETIME(3) or TIMESTAMP(4)? I believe both of these will give you the milliseconds. If you are trying to get the millisecond time where the interatction happens such as the row becomes updated you can use ON UPDATE DATETIME(3)
It seems that Hibernate and MySql interaction removes de milliseconds precision of your Date/Timestamp Java property. I have the same problem.
My solution is to "hack" hibernate telling that the entity property is an string and then serializing/deserializing the value in the setter/getter
#Column(name="time")
private String time
...
public Date getTime(){
return strTodate( this.time );
}
public void setTime(Date value){
this.time = dateToStr( value );
}
When MySQL receives an String for a Datetime(3) column, string is properly converted and milliseconds are not lost :-)
Fortunately, when reading from MySQL, Datetime(3) is propery serialized to string without milliseconds lost
The string date format used is "yyyy-MM-dd hh:mm:ss.SSS"
The idea of this solution is, don't let hibernate deal with dates. Delegate the responsability to MySql.
Unfortunatelly, MySQL doesn't accept an standard ISO string (i.e.: "yyyy-MM-ddThh:mm:ss.SSSZ") and this solution is not compatible with postgres (string date format is not the same)

How do i map a sql Time type to a java type using hibernate?

I've got a sql data type of TIME. Now, the data for 12:00 AM is stored as 00:00:00.
In the POJO that is mapped to the table, I have given the datatype as java.util.Date as per the hibernate specification. However, on loading a row that has the data type 00:00:00 i get this exception.
Cannot convert value '00:00:00' from column 18 to TIMESTAMP
How do I solve this?
For SQLServer you can use something like this. It should also work for time types I guess.(I don't know if it changes for other DB types)
private Date lockedUntil;
#Column(name="DATE", columnDefinition="DATETIME")
#Temporal(TemporalType.TIMESTAMP)
public Date getDate() {
return date;
}