Thorben Janssen @[email protected]
42K subscribers - no pronouns :c
I'm a freelance consultant and trainer helping Java develope
in the future - u will be able to do some more stuff here,,,!! like pat catgirl- i mean um yeah... for now u can only see others's posts :c
Maybe you've already seen on the website that I'm running a special offer for new Persistence Hub members:
Everyone who joins the Persistence Hub before Friday, January 31st, gets my 11 Coding Problems of 2024 for free.
Each Coding Problem gives you a video in which I discuss the problem and different solutions in great detail (incl. questionable ones I've seen in various projects and my preferred solution).
You also get example projects for all solutions so that you can try them yourself and use them as a blueprint for your own projects.
Several members told me that the Coding Problems are extremely useful because they give them a deeper, practical understanding of the features they theoretically know. The detailed explanation of my solution gives them a deep understanding of the combination of features that are used and all their benefits and downsides.
Join the Persistence Hub until Friday and download the Coding Problems 2024 bonus package:
thorben-janssen.com/join-persistence-hub/?utm_sourโฆ
5 - 0
Hibernate maps the most interesting classes of the Date and Time API without any additional mapping annotations.
But working ZonedDateTime and OffsetDateTime can be an issue.
Not all databases support the JDBC type TIMESTAMP_WITH_TIMEZONE. So, Hibernate has to provide a type conversion.
In version 5, Hibernate normalized the timestamp to your local or a configured timezone. And that caused lots of problems.
Starting with version 6, you can decide how to handle the timezone information by providing a TimeZoneStorageType.
The image shows an overview of the different TimeZoneStorageType values and how they affect the mapping.
And if you want a more detailed description, please check the link in the first comment.
25 - 1
Youโve probably heard you should use lazy fetching to avoid performance problems.
But did it solve all your performance problems?
Probably not!
In today's video, I tell you why lazy fetching is only the 1st step and what you have to do next.
๐ฅ Watch it here: https://www.youtube.com/watch?v=QAaTL...
20 - 0
Most Hibernate performance issues are caused by fetching related entities you donโt use in your business code.
To make it even worse, this happens automatically and is extremely hard to find on your typical test system.
In this video, I will show you the critical part of your entity mapping to avoid these problems. And I will also show you a logging configuration that makes these problems visible.
8 - 0
Here's what you need to know about the new Jakarta Data specification:
Jakarta Data standardizes stateless repositories based on Jakarta Persistence and Jakarta NoSQL.
Like all Jakarta specifications, Jakarta Data only provides an API jar that contains everything you need to implement your application.
You need to provide an implementation based on Jakarta Persistence (e.g. Hibernate) or Jakarta NoSQL at runtime.
Starting with version 6.6, Hibernate's metamodel generator supports Jakarta Data. It creates the required implementations of your repositories at compile time.
You can design your own repositories using the lifecycle annotations @Insert, @Update, @Delete, and @Save. The @Query annotation allows you to provide your own query statements.
What do you think about it? Will you use it in your applications?
8 - 1
When migrating to Hibernate 6, you need to know the new implicit naming strategy for database sequences. It changes the default sequence Hibernate uses if you don't set a sequence name.
Here is what you need to do to switch it back or use your own naming strategy.
Set the configuration parameter hibernate.id.db_structure_naming_strategy in your persistence.xml to:
- standard (the default in Hibernate 6)
- legacy (used in Hibernate >=5.3)
- single (used in Hibernate <5.3)
- fully qualified class name of your implementation
<persistence>
<persistence-unit name="my-persistence-unit">
...
<properties>
<property name="hibernate.id.db_structure_naming_strategy" value="standard" />
...
</properties>
</persistence-unit>
</persistence>
๐ต๐ถ๐ฏ๐ฒ๐ฟ๐ป๐ฎ๐๐ฒ.๐ถ๐ฑ.๐ฑ๐ฏ_๐๐๐ฟ๐๐ฐ๐๐๐ฟ๐ฒ_๐ป๐ฎ๐บ๐ถ๐ป๐ด_๐๐๐ฟ๐ฎ๐๐ฒ๐ด๐ = ๐๐๐ฎ๐ป๐ฑ๐ฎ๐ฟ๐ฑ
Hibernate 6 uses a separate database sequence for each entity class by default. The name of that sequence consists of the name of the database table to which the entity class gets mapped and the postfix _SEQ.
๐ต๐ถ๐ฏ๐ฒ๐ฟ๐ป๐ฎ๐๐ฒ.๐ถ๐ฑ.๐ฑ๐ฏ_๐๐๐ฟ๐๐ฐ๐๐๐ฟ๐ฒ_๐ป๐ฎ๐บ๐ถ๐ป๐ด_๐๐๐ฟ๐ฎ๐๐ฒ๐ด๐ = ๐น๐ฒ๐ด๐ฎ๐ฐ๐
This is the strategy used in versions >=5.3. Hibernate uses hibernate_sequence for primary key attributes annotated with @GeneratedValue that don't reference a generator or the name of the referenced generator
๐ต๐ถ๐ฏ๐ฒ๐ฟ๐ป๐ฎ๐๐ฒ.๐ถ๐ฑ.๐ฑ๐ฏ_๐๐๐ฟ๐๐ฐ๐๐๐ฟ๐ฒ_๐ป๐ฎ๐บ๐ถ๐ป๐ด_๐๐๐ฟ๐ฎ๐๐ฒ๐ด๐ = ๐๐ถ๐ป๐ด๐น๐ฒ
The naming strategy single is a simpler version of the legacy strategy and gets you the default naming of Hibernate in versions <5.3. It uses the sequence hibernate_sequence if you donโt specify a sequence name.
๐ต๐ถ๐ฏ๐ฒ๐ฟ๐ป๐ฎ๐๐ฒ.๐ถ๐ฑ.๐ฑ๐ฏ_๐๐๐ฟ๐๐ฐ๐๐๐ฟ๐ฒ_๐ป๐ฎ๐บ๐ถ๐ป๐ด_๐๐๐ฟ๐ฎ๐๐ฒ๐ด๐ = ๐ฐ๐น๐ฎ๐๐ ๐ป๐ฎ๐บ๐ฒ
You can use the same mechanism to provide your own naming strategy. You only need to provide an implementation of the ImplicitDatabaseObjectNamingStrategy interface and configure it in your persistence.xml
๐๐ผ๐ผ๐ธ๐ถ๐ป๐ด ๐ณ๐ผ๐ฟ ๐บ๐ผ๐ฟ๐ฒ ๐ฑ๐ฒ๐๐ฎ๐ถ๐น๐?
Check out my post about the new implicit naming strategies for database sequences in Hibernate 6
thorben-janssen.com/sequence-naming-strategies-in-โฆ
15 - 1
In Java, a List is supposed to be an ordered Collection of elements. But that's not necessarily the case if you're persisting it with Hibernate. By default, it doesn't persist the order of the elements of an ElementCollection or to-many association modeled as a java.util.List.
Before Hibernate 6, you had to use an @OrderColumn annotation to tell Hibernate to store the position of each element of the to-many association or ElementCollection.
@Entity
public class ChessPlayer {
@OneToMany(mappedBy = "playerWhite")
@OrderColumn
private Set<ChessGame> gamesWhite;
@OneToMany(mappedBy = "playerBlack")
@OrderColumn(name="myOrderColumn")
private Set<ChessGame> gamesBlack;
...
}
Since Hibernate 6, you can define this globally for all ElementCollection and the owning sides of many-to-many associations by configuring the property hibernate.mapping.default_list_semantics.
<persistence>
<persistence-unit name="my-persistence-unit">
<description>Hibernate example configuration - thorben-janssen.com</description>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.mapping.default_list_semantics" value="LIST" />
...
</properties>
</persistence-unit>
</persistence>
When doing that, please keep in mind that Hibernate needs to update the position of all elements if you're adding or removing an element that's not the last one. This can require many SQL UPDATE statements and slow down your application.
I explain all of this in more detail in today's blog post: thorben-janssen.com/hibernate...
27 - 0
After my talk at the JavaLand conference, I was asked how to add Flyway to an application that's already deployed in production.
You can easily do that by implementing the following 2 steps:
๐ฆ๐๐ฒ๐ฝ ๐ญ:
Generate a DDL script that recreates your current database with all its schemas, tables, sequences, constraints, ...
Rename that script so that it follows Flyway's naming convention V<VERSION>__<DESCRIPTION>.sql and copy it to your db script folder.
๐ฆ๐๐ฒ๐ฝ ๐ฎ:
Baseline your existing database to create the flyway_schema_history table and store the first version record:
flyway -url=jdbc:postgresql://localhost:5432/codingChallenge-220404
-user=postgres
-password=postgres
-baselineVersion=1
-baselineDescription=initial_version
baseline
This tells Flyway that your db is already in version 1 and prevents it from executing the 1st migration script.
๐๐ป๐ฑ ๐๐ผ๐'๐ฟ๐ฒ ๐ฑ๐ผ๐ป๐ฒ
Flyway will treat an existing database that contains the baseline version in the same way as a new database created using the 1st migration script.
I explained all of this in more detail at thorben-janssen.com/flyway-migration-existing-dataโฆ
20 - 0
Here is a new Hibernate 6 feature you should know: Improved ZonedDateTime & OffsetDateTime mappings
In version 5, the timestamp got normalized to the timezone of your JDBC driver or a configured timezone and stored without timezone info. Now you have multiple mapping options.
You can define your mapping by setting the hibernate.timezone.default_storage property in your configuration or by annotating your entity attribute with @TimeZoneStorage.
Hibernate 6 supports 5 TimeZoneStorageTypes:
๐ง๐ถ๐บ๐ฒ๐ญ๐ผ๐ป๐ฒ๐ฆ๐๐ผ๐ฟ๐ฎ๐ด๐ฒ๐ง๐๐ฝ๐ฒ๐.๐ก๐๐ง๐๐ฉ๐
Maps the ZonedDateTime or OffsetDateTime object to a column of type timestampe_with_timezone.
This is the best mapping but only a few databases support the required column type.
๐ง๐ถ๐บ๐ฒ๐ญ๐ผ๐ป๐ฒ๐ฆ๐๐ผ๐ฟ๐ฎ๐ด๐ฒ๐ง๐๐ฝ๐ฒ.๐ก๐ข๐ฅ๐ ๐๐๐๐ญ๐
Normalizes the timestamp to the timezone of your JDBC driver or the one configured as hibernate.jdbc.time_zone and persists it without timezone info.
This is the same behavior as in #Hibernate 5.
You should always configure a timezone without DST, e.g. UTC
๐ง๐ถ๐บ๐ฒ๐ญ๐ผ๐ป๐ฒ๐ฆ๐๐ผ๐ฟ๐ฎ๐ด๐ฒ๐ง๐๐ฝ๐ฒ.๐ก๐ข๐ฅ๐ ๐๐๐๐ญ๐_๐จ๐ง๐
Normalizes the timestamp to UTC and persists it without timezone information.
This is the better version of TimeZoneStorageType.NORMALIZE.
HHH-15174 prevents the conversion to UTC -> Same behavior as TimeZoneStorageType.NORMALIZE
๐ง๐ถ๐บ๐ฒ๐ญ๐ผ๐ป๐ฒ๐ฆ๐๐ผ๐ฟ๐ฎ๐ด๐ฒ๐ง๐๐ฝ๐ฒ.๐๐ข๐๐จ๐ ๐ก
Persists the timestamp and the timezone offset in 2 separate columns.
This is your best option if your database doesn't support the column type timezone_with_timestamp.
๐ง๐ถ๐บ๐ฒ๐ญ๐ผ๐ป๐ฒ๐ฆ๐๐ผ๐ฟ๐ฎ๐ด๐ฒ๐ง๐๐ฝ๐ฒ .๐๐จ๐ง๐ข
Depending on your database's capabilities, Hibernate uses TimeZoneStorageType.NATIVE or TimeZoneStorageType.COLUMN.
I explained all mapping options in more detail in thorben-janssen.com/hibernate-6-offsetdatetime-andโฆ
24 - 0
I'm a freelance consultant and trainer helping Java developers create better persistence layers for relational databases using Hibernate and Spring Data. Using these frameworks often seems easy, but implementing efficient and maintainable persistence layers is more complicated than it seems. You have to understand how your persistence frameworks work internally to avoid common mapping pitfalls, create efficient queries, and get the best performance.
On my channel, you can expect content focusing on Hibernate and Spring Data JPA. You can also expect videos about Jakarta Persistence, Hibernate Envers, Spring Data JDBC, and other persistence frameworks. Make sure you are subscribed to not miss any videos.
If you have any questions or want to request a video idea, just leave a comment on any video or send an email to [email protected]!
Thanks for watching!