I've recently started using Joda time library for my test project.
Particularly i have been enjoying the capabilities of DateTime and functions for its manipulation.
My query is how do you store DateTime in MySql. I am using Spring & Hibernate for my application.
my current entity throws deserialisation errors whenever I try and use it:
#Entity
#Table(name = "test_storage")
public class TestEntity {
#Id #GeneratedValue
private int id;
#Column
private DateTime testDate;
//getters and setters
}
The mysql table structure is as follows:
Name: test_storage
Columns:
id INT NOT_NULL, AUTO_INCREMENT
testDate DATETIME
Any advice?
If you are using Hibernate 4+, then you can adopt the Jadira user types which allow you to map DateTime (and other JODA date time related class like LocalDate, LocalDateTime etc) to DB fields using different strategies.
Your mapping will look like
public class TestEntity {
//...
#Column
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime testDate;
}
Read the documents to know how to properly use these types to fit your requirements.
The biggest pitfall that you may face soon is, as Java's Date does not include timezone information nor does it sticks to UTC (JODA's user types still need to map to Timestamp/Date internally), you may want to make sure the way you store does provide proper information. For example, either store the date time as UTC, or store timezone information as a separate field, etc.
DATETIME would be my choice. See some more details at What difference between the DATE, TIME, DATETIME, and TIMESTAMP Types and http://infopotato.com/blog/index/datetime_vs_timestamp
Related
I'm trying to make a query to retrieve some data which has been created between two dates (represented as Instant).
Here below an extract from the Entity I'm using:
#Entity
public class HistoricalData {
#Id
#GeneratedValue
private Long id;
#Column
private String name;
#CreationTimestamp
private Instant timestamp;
#Column
private Double price;
}
And the query I've written to retrieve the data between the two Instants;
#Query("select h from HistoricalData h where h.timestamp between :timestampStart and :timestampEnd and upper(name) = upper(:name)")
List<HistoricalData> findHistoricalDataBetween(#NonNull Instant timestampStart, #NonNull Instant timestampEnd, #NonNull String name);
Which produces this SQL query:
select historical0_.id as id1_5_, historical0_.price as price2_5_, historical0_.timestamp as timestam3_5_ from historical_data historical0_ where (historical0_.timestamp between ? and ?) and upper(historical0_.name)=upper(?)
Also I wrote the "hibernate JPA" query just to try but no success:
List<HistoricalData> findHistoricalDataByTimestampAfterAndTimestampBeforeAndName(#NonNull Instant timestampStart, #NonNull Instant timestampEnd, #NonNull String name);
Keep in mind that all the above queries compile correctly and do not throw any exception, they just retrieve nothing from the database
The database I'm using is a latest version of MariaDB and the connector version is the 2.7.2
Also the SpringBoot version I'm using is the 2.5.3
Here is DDL from the table definition (automatically generated from Hibernate):
create table historical_data
(
id bigint not null primary key,
price double null,
timestamp datetime not null,
name varchar not null
);
An this is how the timestamp looks like in the database:
Even though records between those two Instants are present in the database I'm still getting nothing as a result from the query.
Looks like the reason is a time zone.
MySQL driver uses incorrect time zone transformations, using a default local time zone in place of a connection time zone (or vice versa).
Just debug this query inside MySQL driver to have fun and figure out what happens.
You can add parameters to the database URL to see which actual values are passed for the prepare statement
jdbc:mysql://<DATABASE_URL>?logger=com.mysql.cj.log.Slf4JLogger&profileSQL=true
I write application on Spring Boot with Spring Data(postgresql).
I have the following case. I want to store in database time at UTC timezone, and parse it to/from "America/San-Paulo" timezone in dto.
For example: in controller I get dto with LocalDateTime in America/San-Paulo timezone. And I want to save it in database in UTC timezone.
I can do in when mapping from dto to entity. But maybe there is another simple way like setting some properties of hibernate/spring?
Since Java 8, we have the Date/Time API under java.time!
(1) Convert the timezone in annotated #PrePersist, #PreUpdate, and #PostLoad methods.
For example, in annotated #PostLoad, convert from UTC to America/San-Paulo.
private static ZoneId UTC_ZONE = ZoneId.of("UTC");
private static ZoneId LOCAL_ZONE = ZoneId.of("America/San_Paulo");
private LocalDateTime dateTime;
#PostLoad
public void toLocal() {
dateTime = dateTime.atZone(UTC_ZONE).withZoneSameInstant(LOCAL_ZONE).toLocalDateTime();
}
(2) Assuming you are using Jackson, you can write a custom serializer/deserializer.
UPDATE:
With PostgreSQL, you can use the type timestamp with time zone. By default, if you insert/update the column, it will convert the value to UTC.
In JPA:
#Column(columnDefinition = "timestamp with time zone")
UPDATE (22-07-01):
You could also use an AttributeConverter.
required format image
I want to object data into MongoDB using spring and I have hardcoded it.
please how to write a schema for that and I have taken it as an example only.
I have a different type of categories in it I have taken only clothes.
please tell me how to write one schema for a different type of categories and query too.
please find the attachment for your reference
I would recommend going though Spring Data MongoDB documentation for specifics on mapping java objects to MongoDB documents. Your case would look similar to:
#Document
public class Clothes {
#Id
private ObjectId id;
private Men men;
private Women women;
// getters & setters
}
You would need to define each sub class but this should be the gist of it.
What you can do is create a simple POJO (Plain Old Java Object) and with that you can insert that object into the data base. The the following example:
#Document
public class OAuthModel implements Serializable {
#Id
String username;
#Indexed
String oAuthID;
#Indexed
String type;
// Getter and Setters and Construct.
}
When I insert this object in the DB by calling:
OAuthModel authModel = new OAuthModel(username,firebaseToken.getUid(), OAuthHosts.GOOGLE.getType());
oAuthRepo.insert(authModel);
It will then be seen as this in the Database:
Keep in mind this will work no matter what your object looks like, you can have hashmaps etc. The should be a built in serialization.
I'm working on a Hibernate/Spring application to manage some movies.
The class movie has a many to many relationship with the class genre.
Both of these classes have generated id's using the GeneratedValue annotation.
The genre is saved through the movie object by using #Cascade(CascadeType.SAVE_UPDATE)
I have placed a unique constraint on the genre's type attribute (which is it's name; "Fantasy" for example).
What I would like to do now is have Hibernate check if there is already a genre with type "Fantasy" and if there is, use that genre's id instead of trying to insert a new record.
(The latter would obviously throw an error)
Finally what I need is something like select-before-update but more like select-before-save.
Is there such a function in Hibernate?
Some code:
Movie class
#Entity
public class Movie {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#Lob
private String description;
#Temporal(TemporalType.TIME)
private Date releaseDate;
#ManyToMany
#Cascade(CascadeType.SAVE_UPDATE)
private Set<Genre> genres = new HashSet<Genre>();
.... //other methods
Genre class
#Entity
public class Genre {
#Column(unique=true)
private String type;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id
....//other methods
You may be over-thinking this. Any select-before-update/select-before-save option is going to result in 2 DB round trips, the first for the select, and the second for the insert if necessary.
If you know you won't have a lot of genres from the outset, you do have a couple of options for doing this in 1 RT most of the time:
The Hibernate second-level cache can hold many if not all of your Genres, resulting in a simple hashtable lookup (assuming a single node) when you check for existence.
You can assume all of your genres are already existing, use session.load(), and handle the new insert as a result of the row not found exception that gets thrown when you reference a genre that doesn't already exist.
Realistically, though, unless you're talking about a LOT of transactions, a simple pre-query before save/update is not going to kill your performance.
I haven't heard of such a function in Hibernate select-before-update/select-before-save
In situations like these you should treat Hibernate as if it was JDBC.
First if you want to know if you even have such a Genre you should query for it.
if you do. then the SAVE_UPDATE will not create a new one when you add it to a movie.
if you don't, Hibernate will create a new Genre row in the database and add the connection to the many_to_many table for you.
I'm Using Oracle 11g and JPA 2.0 (hibernate in JBoss 6.0.0).
I need to represent a time range in an entity, so I defined those fields:
#Temporal(TemporalType.TIME)
private Date startTime;
#Temporal(TemporalType.TIME)
private Date endTime;
The generated tables use two DATE fields, and this is ok since Oracle doesn't have a type representing just the time part.
When loading the entity from db, just the time part is loaded (the field contains a java.sql.Time).
I've seen instead that if I set a complete date+time in the fields, the date part will be persisted to the db.
Is there a way to ensure that the date part will not be persisted to the db?
You can write setter methods which remove the date component. Quick and dirty example:
public void setStartTime(Date startTime)
{
this.startTime = new Time(startTime.getTime() % 86400000L);
}
Though you'd be better off using Joda Time to do your date/time calculations (see this question). I didn't test this to make sure it's correct, but it should show you the basic idea:
public void setStartTime(Date startTime)
{
this.startTime = new Time(LocalTime.fromDateFields(startTime).millisOfDay().get());
}