I'm mapping a TIME column of a MySQL database in Hibernate (5.4.6.Final) as a java.time.LocalTime class.
This is the declaration of the mapping into the entity:
#Column(name = "TIMEVAL")
public LocalTime TIMEVAL;
The column in the database has value 00:30:00, however Hibernate it's building the instance of TIMEVAL with a value of 01:30:00.
I thought about a difference of time-zones (Ignoring the fact that the TIME data-type doesn't have a time-zone) between the server and the hibernate connection, but I setup each connection and the server as UTC.
And by executing the queries:
SELECT ##global.time_zone;
SELECT ##session.time_zone;
The result of the Hibernate session and the server were all +00:00.
Following the Hibernate configuration:
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
spring.datasource.url=jdbc:mysql://localhost:3306/..?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&allowMultiQueries=true
And here's the MySQL configuration:
default-time-zone=+00:00
I tried also:
Specifying the MySQL column as VARCHAR(8), but Hibernate always retrieves 01:30:00;
Changing the Entity data-type to Duration, but Hibernate throws an error saying that it can't map TIME to java.lang.Long.
What do I need to modify in order to have Hibernate build the LocalTime instance with the value of the database column?
As #Andreas pointed out in the comments. The JVM time zone wasn't in UTC.
I needed to change the JVM time zone to get the correct value out of the database.
So, by adding the following param to the JVM options:
-Duser.timezone=UTC
Finally the LocalTime instance was built with the value of 00:30:00 as the value of the database column.
Related
In a MySQL DB every table has a column updated which is created as
[...] `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
As expected, every row update does trigger the timestamp's update to the CURRENT_TIMESTAMP. This is true when I update a row via the SQL shell, command line, DBeaver, Workbench BUT
Working with Hibernate (Spring Boot 2, Spring Data JPA) does not work. I mean, pseudocode such as:
[Tx]
entity = repository.findById(1) --> Returns my entity with updated == 1L
entity.setProperty("other value")
repository.save(entity)
[/Tx]
At this point, the DB entry has been updated ("other value" is the current value) but the updated column is still 1L where should be CURRENT_TIMESTAMP
I used to bypass this problem either
annotating the property as #UpdateTimestampor h
annotating a method with #PrePersist && #PreUpdate which would programatically set the current timestamp before the UPDATE SQL statement
The problem with both approaches is that I don't have the updated value until out of my Tx:
[Tx]
entity.getUpdated() == 1L
entity.setName("other")
repository.save(entity) // at this point the updated is still == 1L
repository.findById() // at this point the updated is still == 1L
[/Tx]
[Tx]
repository.findById() // good timestamp value
[Tx]
Is it normal that MySQL doesn't trigger the update in the first place?
Is there a way to fetch the updated value in the same transaction?
You need JPARepository.saveAndFlush() (or with raw JPA, EntityManager.refresh()) to get the updated value from the database in the same transaction. This affects all database generated values.
JPA doesn't know that values are changing inside the database, and it would be bad for performance to always re-read the saved value. That's why in a new transaction you get the correct values, as the data is actually fetched from the database. In the same transaction the value is still in memory and assumed to be unchanged.
I totally fail when i want use this data type. I get exception:
Unknown data type: "DATETIMEOFFSET"; SQL statement:
ALTER TABLE PUBLIC.usr_user ALTER COLUMN next_password_change_date DATETIMEOFFSET [50004-196]
Is there any way around that?
Unfortunately, there is no DATETIMEOFFSET data type in h2 like in SQL server.
Reference: http://www.h2database.com/html/datatypes.html
Way around that will be to choose a different date type e.g. DATE, TIMESTAMP or TIMESTAMP WITH TIME ZONE.
I'm using PostgreSQL 8.4, and the server is linux, and the linux's time zone is'EDT' not 'UTC'. The configuration of PostgreSQL make the DataBase's time zone to 'UTC'. The code is running on JBoss9.
I have one sql, select to_char(ts_entry.submitted_date, 'MM/DD/YYYY HH24:MM') as submitted_date_format from ts_entry where ....
If we run the sql in PostgreSQL, we will get the value, "07/10/2017 02:07"
But when I try to get the value from resultSet in java,
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(sql);
String value = rs.getString("submitted_date_format");
The value will be "07/09/2017 22:07".
The origin value in DB is "2017-07-10 02:02:25.268+00".
How can I handle the effect caused by linux server's timezone in code level?
BTW, I know an alternative solution, change the start up scripts of jboss, to make the jboss to start up using timezone 'UTC'. Can this issue be handled in code level?
The Database server machine's time zone has no direct impact on the behaviour, except that it is used to initialize timezone in postgresql.conf, which is the initial setting for the client time zone unless overridden by the database session.
PostgreSQL stores timestamp with time zone in UTC internally and converts it to the client's local time zone upon delivery.
So you should set the database session time zone the way you need with
SET TIME ZONE '<time zone name>';
That will convert dates to that time zone when you select then from PostgreSQL.
In a postgres db, using jOOQ, when I fetch a row that has a column defined as
timestamp without time zone
when I do a select and I get the value (fetched by jOOQ into a java.sql.Timestamp), then I see that the nanoseconds are missing.
E.g., in the database I have:
2016-04-04 15:14:10.970048
but jOOQ returns a Timestamp with value
2016-04-04 15:14:10.0
This is a problem for further comparisons. How can I prevent this?
UPDATE
Upon request, I'll provide more details.
In Postgresql I have a type:
CREATE TYPE schema.my_type AS
(
mt_page smallint,
mt_active_from timestamp without time zone,
);
I call a function, using the routines:
DSLContext dsl = ....
MyTypeRecord [] records = Routines.myRoutine(dsl.configuration);
Then, the Timestamp will not have no nanos
The function is:
CREATE OR REPLACE FUNCTION shop.myRoutine(
OUT my_types schema.my_type[]
)
RETURNS schema.my_type[] AS
$BODY$
DECLARE
BEGIN
BEGIN
SELECT ARRAY(
SELECT
ROW(a_id, a_timestamp)::schema.my_type
FROM schema.article
) INTO my_types;
END;
RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 1000;
This is a bug in jOOQ: https://github.com/jOOQ/jOOQ/issues/5193
jOOQ internally implements a composite type deserialisation algorithm, as PostgreSQL's JDBC driver, unfortunately, doesn't implement SQLData and related API for out-of-the-box composite type support. The current implementation (jOOQ 3.7.3) parses timestamps without their fractional seconds part.
As a workaround, you could implement your own data type binding to work around this issue.
I'm trying to get an interval through an operation with Timestamps from a table but I'm getting a "No Dialect mapping for JDBC type: 1111"
The code is like this:
SELECT TS_FINISH - TS_START FROM TABLE
Where TS_FINISH and TS_START are Timestamps
I used a function from my DBMS to cast the result to a text.
Unfortunately there is no hql function that does it.