hibernate Miscs
hibernate overview
JPA Vs Hibernate
The Java Persistence API, or JPA, is a specification that defines the management of relational data in a Java application. The API maps out a set of concepts that defines which objects within the application should be persisted, and how it should persist them.
JPA is only a specification and that it needs an implementation to work
With JPA specification defining how and what we should persist, we now need to choose an implementation provider to supply the necessary code.
Providers
- hibernate
- Eclipse Link
As you state JPA is just a specification, meaning there is no implementation. You can annotate your classes as much as you would like with JPA annotations, however without an implementation nothing will happen. Think of JPA as the guidelines that must be followed or an interface, while Hibernate's JPA implementation is code that meets the API as defined by the JPA specification and provides the under the hood functionality.
When you use Hibernate with JPA you are actually using the Hibernate JPA implementation. The benefit of this is that you can swap out Hibernate's implementation of JPA for another implementation of the JPA specification. When you use straight Hibernate you are locking into the implementation because other ORMs may use different methods/configurations and annotations, therefore you cannot just switch over to another ORM.
https://stackoverflow.com/questions/9881611/whats-the-difference-between-jpa-and-hibernate
https://www.baeldung.com/jpa-hibernate-difference
Hibernate.initialize
A LazyInitializationException
will be thrown by Hibernate if an uninitialized collection or proxy is accessed outside of the scope of the Session, i.e., when the entity owning the collection or having the reference to the proxy is in the detached state.
Solution
- use eager loading
- do not close the session until job is done
- fetch require data before session is closed
Sometimes a proxy or collection needs to be initialized before closing the Session. One way is to force initialization by calling entity.getXXX()
or entity.getXXX().size()
, for example. However, this can be confusing to readers of the code and it is not convenient for generic code.
Hibernate.initialize()
and Hibernate.isInitialized()
, provide the application with a convenient way of working with lazily initialized collections or proxies. Hibernate.initialize(entity.getXXX())
will force the initialization of a proxy, entity.getXXX()
, as long as its Session is still open. Hibernate.initialize( )
has a similar effect for the collection of entities as well.
Without second level cache
due to the call to the Hibernate.initialize
method, a secondary SQL query is executed to fetch the Post
entity, and that’s not very efficient and can lead to N+1 query issues.
if you’re not using the second-level cache, it’s not a good idea to fetch lazy associations using secondary SQL queries either by traversing them or using the Hibernate.initialize
method.
With second level cache
f you are using the second-level cache, it’s fine to use the Hibernate.initiaize
to fetch extra associations that you need to fulfill your business use case. In this case, even if you have N+1 cache calls, each call should run very quickly since the second-level cache is configured properly and data is returned from the memory.
The Hibernate.initialize
can be used for collections as well. Now, because second-level cache collections are read-through, meaning that they are stored in the cache the first time they get loaded when running the following test case:
date
1. util.date Vs sql.data
The *java.util.Date* class represents a particular moment in time, with millisecond precision since the 1st of January 1970 00:00:00 GMT (the epoch time).
With the introduction of Java 8, *java.time* package should be used. Prior to Java 8, an alternative solution was available – Joda Time.
The *java.sql.Date* extends *java.util.Date* class.
java.sql.Date
corresponds to SQL DATE which means it stores years, months and days while hour, minute, second and millisecond are ignored. Additionallysql.Date
isn't tied to timezones.java.sql.Time
corresponds to SQL TIME and as should be obvious, only contains information about hour, minutes, seconds and milliseconds.java.sql.Timestamp
corresponds to SQL TIMESTAMP which is exact date to the nanosecond (note thatutil.Date
only supports milliseconds!) with customizable precision.
2. Hibernate DateTime
https://www.baeldung.com/hibernate-date-time
使用sql date (not a good choice)
private java.sql.Date sqlDate; |
使用util date
util date不是直接map到 sql type, 使用@Temporal annotation(DATE, TIME or TIMESTAMP, ) 映射到对应的sql type
|
java8 new DateTime API
Since Java 8, the new Java Date and Time API is available for dealing with temporal values. This API fixes many of the problems of java.util.Date and java.util.Calendar classes.
The types from the java.time package are directly mapped to corresponding SQL types. So there's no need to explicitly specify @Temporal annotation:
- LocalDate is mapped to DATE
- LocalTime and OffsetTime are mapped to TIME
- Instant, LocalDateTime, OffsetDateTime and ZonedDateTime are mapped to TIMESTAMP
|
https://www.baeldung.com/java-util-date-sql-date
https://stackoverflow.com/questions/2305973/java-util-date-vs-java-sql-date
enum
https://docs.jboss.org/hibernate/orm/5.0/mappingGuide/en-US/html_single/#d5e678
可以使用AttributeConverter
|
Hibernate Vs JDBC
JDBC
the JDBC template will probably be a bit faster, because it doesn't have the overhead that Hibernate has. But it will probably take much more time and lines of code to implement.
Hibernate
Hibernate has its learning curve, and you have to understand what happens behind the scenes, when to use projections instead of returning entities, etc. But if you master it, you'll gain much time and have cleaner and simpler code than with a JDBC-based solution.
Equality
https://howtodoinjava.com/hibernate/hibernate-entities-equality-and-identity/
Objects fetched from same session
Requesting a persistent object again from the same Hibernate session returns the same Java instance of a class, which means that you can compare the objects using the standard Java ‘==’ equality syntax.
Objects fetched from different sessions
if you request a persistent object from more than one Hibernate session, Hibernate will provide distinct instances from each session, and the == operator will return false if you compare these object instances.
Solution : overriding equal and hashcode
Hibernate wraps the actual object in a proxy so always use the getter methods inside instead of actual properties to compare.
OrphanRemoval
Orphan Removal – when a target entity in one-to-one or one-to-many relationship is removed from the relationship, it is often desirable to cascade the remove operation to the target entity.
Example: if an order has many line items and one of them is removed from the order, the removed line item is considered an orphan. If orphanRemoval is set to true, the line item entity will be deleted when the line item is removed from the order.
Orphan Removal Vs Cascade Delete
Cascade Delete removes all children when parent is removed. So, If you delete user entity, JPA deletes all his photos too.
Orphan Removal removes corresponding child when you remove it from the relationships. So, if you delete 1 photo from user.getPhotos() collection, JPA automatically removes that photo from database too.
Notes**: 可以code 里来handle 关联删除, 而非依赖于hibernate 自动做。
Batch
https://www.baeldung.com/jpa-hibernate-batch-insert-update
Hibernate doesn't enable batching by default. This means that it'll send a separate SQL statement for each insert/update operation:
|
we should set *hibernate.jdbc.batch_size* property to a number bigger than 0.
Batch Insert Without Explicit Flush
@Transactional |
Issue:
. When we persist an entity, Hibernate stores it in the persistence context. For example, if we persist 100,000 entities in one transaction, we'll end up having 100,000 entity instances in memory, possibly causing an OutOfMemoryException.
Batch Insert with Explicit Flush
First of all, the persistence context stores newly created entities and also the modified ones in memory. Hibernate sends these changes to the database when the transaction is synchronized. This generally happens at the end of a transaction. However, calling *EntityManager.flush()* also triggers a transaction synchronization.
Secondly, the persistence context serves as an entity cache, thus also referred to as the first level cache. To clear entities in the persistence context, we can call EntityManager.clear().
Transactional |
Hibernate Validator
Bean validation API 2 (JSR-380
) offers some popular annotations that can be attached to each bean property for the purpose of maintaining data integrity.
<!-- Java bean validation API - Spec --> |
|