Hibernate store YearMonth in MySQL as Blob instead of text - mysql

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?

Related

Store large binary in database(MySQL, PSQL, etc) using Spring boot

I want to store large binary files in Databases such as MySQL, PSQL, etc in Spring boot. I have
I am using following type in DAO
#Lob
#Type(type = "org.hibernate.type.BlobType")
#Column(name = "document", nullable = false, length=50000000)
private Blob document;
In PSQL, document column type is stored as oid
In MySQL, document column type is stored as longblob
I am trying to use following code for PSQL. Refer here
LargeObjectManager lobj = conn.unwrap(org.postgresql.PGConnection.class).getLargeObjectAPI();
Is there any equivalent for PGConnection in MySQL?
Also Will MySQL supports oid type. I see it as longblob

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.

how to do batch insert/update with Springboot data JPA and Mysql

I'm trying to implement batch insert/update records with SpringBoot Data Jpa with Mysql,
here is my yml config:
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_size=500
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true
spring.jpa.properties.hibernate.generate_statistics=true
And I use an mysql auto increment column as primary key, here
public class Customer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
I've googled that batch ops will not work with GenerationType.IDENTITY,
but also I notice that mysql not support GenerationType.SEQUENCE
then how could I accomplish bath insert/update with jpa's saveAll(data) method with mysql DB
Thank you
I've googled that batch ops will not work with GenerationType.IDENTITY, but also I notice that mysql not support GenerationType.SEQUENCE
Set the id in the application. For example using a UUID

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.

hibernate TemporalType ,datetime column mapping

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.