Channel Avatar

Thorben Janssen @[email protected]

42K subscribers - no pronouns :c

I'm a freelance consultant and trainer helping Java develope


Welcoem to posts!!

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

Thorben Janssen
Posted 4 months ago

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

Thorben Janssen
Posted 6 months ago

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

Thorben Janssen
Posted 8 months ago

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

Thorben Janssen
Posted 8 months ago

I'm working on this week's video and was wondering which title you're more likely to click

8 - 2

Thorben Janssen
Posted 8 months ago

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

Thorben Janssen
Posted 11 months ago

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

Thorben Janssen
Posted 3 years ago

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

Thorben Janssen
Posted 3 years ago

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

Thorben Janssen
Posted 3 years ago

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

Thorben Janssen
Posted 3 years ago

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