Hibernate

Hibernate uses PreparedStatement exclusively, so not only it protect against SQL injection, but the data access layer can better take advantage of server-side and client-side statement caching as well.

πŸ’‘ When you open a transaction => you have a Persistence context, where retrieved entities are kept (entities manipulated by EntityManager). When transaction is closed => persistence context is also closed. Session = Persistence context.

Write-behind cache

The Persistence Context acts as a transactional write-behind cache, deferring entity state flushing up until the last possible moment.

Because every modifying DML statement requires locking (to prevent dirty writes), the write behind cache can reduce the database lock acquisition interval, therefore increasing concurrency.

But caches introduce consistency challenges, and the Persistence Context requires a flush prior to executing any JPQL or native SQL query (as otherwise it might break the read- your-own-write consistency guarantee).

Session flush()

session in-memory state -> database

Happens automatically for cases:

  • before query execution

  • when transaction is committed

JPA entity state

The Persistence Context captures entity state changes, and, during flushing, it translates them to SQL statements. The JPA EntityManager and the Hibernate Session (which includes additional methods for moving an entity from one state to the other) interfaces are gateways towards the underlying Persistence Context, and they define all the entity state transition operations.

Hibernate entity state

Relationship

One to one

Which table has a foreign key => this table owning a relation

It will result in following DB structure: Student: | id | name | passport_id | <= ⚠️ owing a relationship Passport: | id | number |

ℹ️ @OneToOne relationship fetch is always eager (fulfilled entity is returned, with opposite entity)

Lazy fetch

Bidirectional relation

It will result in following DB structure: Student: | id | name | passport_id | Passport: | id | number | student_id | 🚫 This is bad because of data duplication.

πŸ‘ It will result in following DB structure: Student: | id | name | passport_id | Passport: | id | number |

Many to one

It will result in following DB structure: Course : | id | name | Review: | id | rating | course_id |

Many to many

Inheritance

Single table

  • it is good that it is single table (better for performance!!)

  • it is bad that there are many nullable columns

Table per class

Concrete table for each subclass are created
  • many tables may be created because of many subclasses

  • Not a good choice (c)

Joined

  • fields from super class are stored into EMPLOYEE table

  • subclass columns are stored in separate tables

  • db design is clear

  • performance may be poor in fetching all kinds of employees (many joins will happen)

  • Better for data integrity

Mapped super class

JPQL

Criteria queries

Transactions

Atomicity, Concurrency, Isolation, Durability

Dirty Read

Non Repeatable Read

Phantom Read

Read Uncommited

possible

possible

possible

Read Commited

(lock on specific value in row)

SOLVED

possible

possible

Repeatable Read

(whole row is locked)

SOLVED

SOLVED

possible

Serializable

(any row matching constraint is locked)

SOLVED

SOLVED

SOLVED

Spring Transactional

is logically equal to

Redundant save() invocation

When a method is transactional, then entities retrieved within this transaction are in the managed state, which means that all changes made to them will be populated to the database automatically at the end of the transaction. Therefore either the save() call is redundant

Ignored Transactional annotation

For Spring in order to take an action on transactions two expected criteria:

  • The method visibility can’t be any other than public.

  • The invocation must come from outside of the bean.

This is due to how Spring proxying work by default (using CGLIB proxies).

When you auto-wire a bean of type Sample, Spring in fact doesn’t provide you exactly with an instance of Sample. Instead, it injects a generated proxy class that extends Sample (yes, that’s the reason why you can’t make your spring bean classes final) and overrides its public methods to be able to add extra behaviour (like transactional support).

Solution 1

  • Extract the method to another class and make it public.

Solution 2

  • Use AspectJ weaving instead of default proxy-based Spring AOP. AspectJ is capable of working with both: non-public methods and self-invocations.

Solution 3 (only for self-invocation)

  • Disclaimer: I wouldn’t use this β€œsolution” in the production code.

Rollbacks

The rule when transaction rollbacks are triggered automatically is very simple but worth reminding: by default, a transaction will be rolled back if any unchecked exception is thrown within it, whereas checked exceptions don’t trigger rollbacks.

We can customize this behaviour with parameters:

  • noRollbackFor - to specify runtime exception, which shouldn’t cause a rollback

  • rollbackFor - to indicate which checked exception should trigger rollbacks

Last updated

Was this helpful?