项目作者: mpuening

项目描述 :
Learn JPA Hibernate
高级语言: Java
项目地址: git://github.com/mpuening/learn-jpa-hibernate.git
创建时间: 2019-09-11T06:25:49Z
项目社区:https://github.com/mpuening/learn-jpa-hibernate

开源协议:Apache License 2.0

下载


Learn JPA Hibernate

Continuous Integration

  1. Note: I have three disabled test cases, due to some bug with class hierarchies: look for:
  2. @Disabled("FIXME_HIBERNATE_DELETE_BUG_ON_CLASS_HIERARCHY ???")
  3. The delete statement is never executed, despite respository.delete(entity) being called.

When Hibernate first came out, I heard people say that it is the future and all your
code should use Object Relational Mapping (ORM). Every now and then today, I hear someone
say that JPA/Hibernate sucks and should never be used. The truth is that JPA/Hibernate
is a nice tool that can be useful in some circumstances and be absolutely dreadful in
others. Developers just need to recognize when and where it can be appropriate and useful.

In order to make an intelligent decision about using JPA though, you need to know to
know the framework. What is sad though is that I meet too many developers that do not
know it very well, or still think JPA has not progressed beyond version 1.0. So if you
do not know JPA very well, and need to get an application written quickly, do not use
it… use JDBC instead.

But if you have time to learn and know JPA, and find you have a data model that dove
tails nicely with an object model, JPA can help you write an application faster with
less code.

So what is in this project?

This project contains several modules that demonstrates different aspects of JPA.

learn-jpa-hibernate-java2ddl

Because JPA implements ORM, there theoretically exists a way to translate your Java
Entity Beans to DDL, and vice versa, create Java Entity Beans from DDL.

One use case for JPA is quickly implementing an application without regards to how the
database schema looks. But should the application show value, you may want to look
at the schema. This can be for several reasons above and beyond the curiosity of reviewing
the schema. For example, your company may have a policy that only DBA’s can implement
schema changes. Another example is that you may want to track schema changes via Flyway
or Liquibase. Being able to get a DDL file from your object model is an essential skill
and the learn-jpa-hibernate-java2ddl project shows how that is done.

The project contains a simple object model of three entity beans. There is a Spring
Boot test case that demonstrates that the model works. The project also contains a DDLExporter
class that can be used to export a DDL file from an object model. There is also a test
case to show that it works.

If you want DDL from your Java Entity Beans, just use the DDLExporter. The code is not
terribly complex. The code is based on Spring to boot up a SessionFactory from which
a metadata source model is obtained. Once you have the metadata, the SchemaExport
class is used to generate the DDL file. Note that the DDLExporter is Hibernate specific.

The learn-jpa-hibernate-swap-in-eclipselink project contains commented out configuration
in the application.yml file that makes EclipseLink generate create-schema.sql and
drop-schema.sql files for the entity beans in its project.

The learn-jpa-hibernate-swap-in-openjpa project also contains commented out configuration
in the application.yml file that makes OpenJPA generate schema but its output is
in the logs and not as a file.

learn-jpa-hibernate-ddl2java

Going in the opposite direction from starting with Java code is starting with an existing
database schema, or at least “schema first” design.

With Hibernate, this direction is not well maintained, and your mileage will vary depending
on how your schema is designed. Not all the relationships are detected or even implemented
and the code that is generated is not formatted very well or even look modern. But,
you are not paying for this tool, and it can get you a decent percentage down the road
towards code complete. Also, I don’t recommend using this tool to produce generated code;
meaning using the code as is, and never modifying it. No, take the code that is produced
and clean it up and make it your own, and never think about using the tool to create
subsequent versions.

Here are the steps to create code for yourself:

  • Identify where your schema is. This project as is, uses an in-memory H2 database with
    the schema located in src/hbm/schema.sql file. If you have the schema as a file, and H2
    will suffice as a database to read the schema file, then copy in your schema into
    that file. If you have an existing database, then ignore schema.sql file and instead
    update the src/hbm/hibernate.properties file with your connection information. Also,
    update pom.xml with a database driver that can connect to your database. Also, of
    big importance, note there is an ant plugin step to create a database from the schema.sql
    file. If you have an existing database and are not creating one, then comment out
    or delete the sql task in pom.xml.
  • Update src/hbm/hibernate.reveng.xml to reference the schema and tables that you
    want to reverse engineer (generate code). Also, checkout the documentation for the
    file, as it might help you generate code more correctly should the out of the box
    settings not suffice.
  • Update the packagename attribute on the jdbcconfiguration element to your desired
    Java package name.
  • Update the JavaCodeGeneratedTest to test for the classes that you expect to generate.
    If you don’t want to update the test case, make sure to run maven with the -DskipTests=true
    flag.
  • To generate your code, run mvn clean package. When complete (and the test cases can
    see your files), you will find your Java code in the target/codegen folder.

Review the code that gets generated and see if there are improvements to be made. Check
that all the relationships are identified and implemented properly. If they aren’t, you might
consider checking if another database can be used to generate code from. For example, the
example in this project has a many to many relationship between Book and Author.
While H2 can detect the relationship, Derby does not. This is why I say your
mileage may vary. Perhaps you can play around with the schema or the database type to
move passed the issue. But don’t take too long. It isn’t terribly difficult to write
Java code with JPA relationships. There is a reason why the DDL to Java Code conversion
library isn’t maintained very well.

learn-jpa-hibernate-equals-and-hashcode

There is an enormous amount of discussion on the internet about whether or not you need
to implement equals() and hashCode() on your entity beans. Below are just a few links:

  • https://vladmihalcea.com/the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate/
  • https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
  • https://vladmihalcea.com/hibernate-facts-equals-and-hashcode/
  • https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma

I have seen many simple projects get away without implementing them, and they satisfied
the requirements. But I have also seen projects with related entity beans that require having
proper implementations for updates to work.

Fortunately implementing the code is easy (as is seen in the above links). The Spring
Data project even provides an AbstractPersistable class from which to extend from and
it implements the code you need. However, that AbstractPersistable takes a strong
opinion on the Id column. Spring’s take on it may not be what you want, so that is
why this project includes a similar AbstractEntity class. It has the equivalent
implementations of equals() and hashCode() but leaves the definition of the Id
to the class that extends from it.

The examples in this project all use that AbstractEntity class (except for the bad
test cases).

This project also includes an EntityValidator utility class that can be used to ensure
that your implementations of equals() and hashCode() methods work properly for entity
beans.

Lombok

It should be pointed out that Lombok and its convenient @Data annotation can cause
problems for entity beans. The @Data annotation provides not only getter and setter
methods, but also implementations of equals(), hashCode() and toString(). These
implementations are wrong for entity beans as the EntityValidator can show.
When using Lombok in your project, have the entity beans just use @Getter and @Setter
and let AbstractPersisable or AbstractEntity provide the equals(), hashCode()
and toString() implementations.

learn-jpa-hibernate-relationships

This project contains a contrived data model that demonstrates each of the relationship
types (e.g. one to many uni-directional and bi-directional). Spring Boot is used to
bootstrap the app, and expose a REST API. The data model is inspired from the O’Reilly’s
Enterprise JavaBeans book (5th Edition) and is a Star Trek themed reservation system. Please
do not evaluate this model as being the best ever, because it exists to show how to implement
each of the JPA relationship types and play with different configuration settings as opposed
to being the best data model. Some parts of model may seem a bit awkward, but at least there
is a working relationship type to test.

Consider the following when building your own model:

Multiplicity

Multiplicity describes how many entities appear in a relationship. In JPA, the multiplicity
is either one or many.

Direction

The direction describes how one can navigate a relationship. In JPA, there are uni-directional
and bi-directional relationship.

Aggregation versus Composition

Aggregation describes a relationship where the child entity may exist independently of the parent
entity. For example, a university has both students and courses, and they are related
when a student enrolls in a course. Deleting a student does not mean the course is deleted,
it just means the student dropped out. Likewise, deleting a course does not mean the
students get deleted. It just means the course isn’t offered anymore.

Composition describes a relationship where the child entity cannot exist independently of the parent
entity. For example, an apartment building consists of apartments. If one were to delete
the building, then the apartments would not exist either.

In JPA, relationships can have an orphanRemoval setting that can be used to determine
what might happen to orphans. The flag should be used judiciously.

Relationship Fetch Type

Below are the JPA defaults for FetchType:

  • OneToMany and ManyToMany relationships are FetchType.LAZY relationships by default.
  • OneToOne and ManyToOne relationships are FetchType.EAGER relationships by default.

Changing the default settings change what queries are done. For example, a one to one
relationship will typically generate inner joins or left outer joins to pull in extra
data from child entities in order to minimize the number of queries. But this costs more
data to queried than might be necessary for a use case. If one we change a relationship
to lazy, less data is queried initially, but additional queries may be executed to
traverse the relationship which might impact performance in another way, for example
the N+1 query problem. FetchType is a static configuration that one must choose wisely.
Dynamic configuration is preferred which is why one should know and understand entity
graphs and projections.

Land Mines and Pitfalls

Consider the following:

  • Prefer Set rather than List for relationships.
  • Avoid OneToMany uni-directional relationships. Set up bi-directional or element collection
    relationships instead.
  • Avoid CascadeType.REMOVE (and CascadeType.ALL) settings on OnetoMany and ManytoMany
    relationships. Implement a bulk delete on child entity table.
  • Learn to recognize the N+1 problem

Example Data Model

Below is the class diagram our model. The arrows between classes are labeled as being
many or one and show whether they are uni-directional or bi-directional.

alt text

Below are sections to help you identify where in the model an example is of each of the
seven JPA relationship types:

1) One-to-One Uni-directional Relationship

Person to Address represents a one to one relationship. This means a person has
one and only one address and an address has only one person. Furthermore, the relationship
can only be navigated from the person side. The code below also indicated that the address
is required and all operations are cascaded (such as delete).

Code (with unrelated properties removed for clarity):

  1. @Entity
  2. @Table(name = "PERSON")
  3. public class Person {
  4. // Join column exists in this entity
  5. @OneToOne(optional = false, cascade = CascadeType.ALL, orphanRemoval = true)
  6. @JoinColumn(name = "ADDRESS_ID", nullable = false)
  7. private Address address;
  8. }
  9. @Entity
  10. @Table(name = "ADDRESS")
  11. public class Address {
  12. // No code required
  13. }

2) One-to-One Bi-directional Relationship

Ship to Customer represents a one to one bidirectional relationship. This relationship
is similar in regards to the multiplicity of the previous relationship, but expands on it by
allowing navigation from both sides.

Code (with unrelated properties removed for clarity):

  1. @Entity
  2. @Table(name = "PERSON")
  3. public class Person {
  4. // Bi-directional relationship has 'mappedBy' attribute in other entity
  5. @OneToOne(optional = true, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
  6. @JoinColumn(name = "SHIP_ID", nullable = true)
  7. private Ship ship;
  8. }
  9. @Entity
  10. @Table(name = "SHIP")
  11. public class Ship {
  12. @OneToOne(mappedBy = "ship", optional = false)
  13. private Person person;
  14. }

3) One-to-Many Uni-directional Relationship

  1. Warning!!!

One to many uni-directional relationship should be avoided. More information can
be found here:

https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/

Customer to HailingFrequency can be considered to be a one to many relationship.
But because of the problems that Hibernate has with dealing with this relationship, it does NOT appear
in the code of this project. It has been switched to a bidirectional relationship with
the child HailingFrequency entity not having a generated Id. It also has a nice example
with using a @PrePersist method to copy the the generated Id into the composite key.

  1. Warning!!!

Even though the relationship was improved upon, it does have an N+1 issue on the cascade
delete operation. Make sure to implement a bulk delete of the child entities when implementing
such a relationship.

Despite the discussion above, here is some sample code of such a relationship
(with unrelated properties removed for clarity):

  1. @Entity
  2. @Table(name = "PERSON")
  3. public class Person {
  4. // Join column exists in the other entity (or join table)
  5. @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  6. @JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "ID")
  7. private Set<HailingFrequency> hailingFrequencies = new HashSet<>(0);
  8. }
  9. @Entity
  10. @Table(name = "HAILING_FREQUENCY")
  11. public class HailingFrequency {
  12. // No code required
  13. }

4) Many-to-One Uni-directional Relationship

Address to Planet represents a many to one relationship. This means that there are many
addresses for each planet, however navigation is only from the address side.

Code (with unrelated properties removed for clarity):

  1. @Entity
  2. @Table(name = "ADDRESS")
  3. public class Address {
  4. // Join column exists in this entity
  5. @ManyToOne(optional = false)
  6. @JoinColumn(name = "PLANET_ID", nullable = false)
  7. private Planet planet;
  8. }
  9. @Entity
  10. @Table(name = "PLANET")
  11. public class Planet {
  12. // No code required
  13. }

5) One-to-Many and Many-to-One Bi-directional Relationship

Voyage to Reservation represents both the one to many and many to one relationship,
because both relationship are the same, just from opposite perspectives.

Code (with unrelated properties removed for clarity):

  1. @Entity
  2. @Table(name = "RESERVATION")
  3. public class Reservation {
  4. // Bi-directional relationship has 'mappedBy' attribute in other entity
  5. @ManyToOne
  6. @JoinColumn(name = "VOYAGE_ID", nullable = false)
  7. private Voyage voyage;
  8. }
  9. @Entity
  10. @Table(name = "VOYAGE")
  11. public class Voyage {
  12. @OneToMany(mappedBy="voyage")
  13. private Set<Reservation> reservations = new HashSet<>(0);
  14. }

6) Many-to-Many Uni-directional Relationship

Reservation to Cabin represents a many to many relationship. The many to many relationship
requires a join table. Being unidirectional means that the relationship is only navigated
from one side. In other words, a cabin cannot navigate to its reservation.

Code (with unrelated properties removed for clarity):

  1. @Entity
  2. @Table(name = "RESERVATION")
  3. public class Reservation {
  4. // This relationship requires a join table
  5. @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
  6. @JoinTable(name = "RESERVATION_CABIN", joinColumns = @JoinColumn(name = "RESERVATION_ID"), inverseJoinColumns = @JoinColumn(name = "CABIN_ID"))
  7. private Set<Cabin> cabins = new HashSet<>(0);
  8. }
  9. @Entity
  10. @Table(name = "CABIN")
  11. public class Cabin {
  12. // No code required
  13. }

7) Many-to-Many Bi-directional Relationship

Reservation to Person represents a many to many bidirectional relationship. This relationship
is similar in regards to the multiplicity of the previous relationship, but expands on it by
allowing navigation from both sides.

Code (with unrelated properties removed for clarity):

  1. @Entity
  2. @Table(name = "RESERVATION")
  3. public class Reservation {
  4. // Bi-directional relationship has 'mappedBy' attribute in other entity
  5. @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
  6. @JoinTable(name = "RESERVATION_PERSON", joinColumns = @JoinColumn(name = "RESERVATION_ID"), inverseJoinColumns = @JoinColumn(name = "PERSON_ID"))
  7. private Set<Person> passengers = new HashSet<>(0);
  8. }
  9. @Entity
  10. @Table(name = "PERSON")
  11. public class Person {
  12. @ManyToMany(mappedBy = "passengers")
  13. private Set<Reservation> reservations = new HashSet<>(0);
  14. }

Other Interesting Features

  • @DiscriminatorColumn Column

    The PERSON table contains a discriminator column for both passengers and captains of ships.

  • @PrePersist

    An example of using @PrePersist is in the HailingFrequency entity class. The method
    is responsible for making sure the Id key property is properly set from the foreign
    key relationship.

  • Currency (MonetaryAmount)

    Hibernate has features that have not been exposed through the JPA API.One of those
    features is Type mapping. On the Cabin entity class is a property called price.
    Even though it is implemented as one property, it is stored as two columns in the database.
    One column for the monetary amount and another for currency type. It even stores the numeric
    value in the minor amount (e.g. pennies) so that the database doesn’t lose fractions of pennies.
    (Remember Superman III?). You can find the logic to support the type in MonetaryAmountUserType.

    In addition, the MonetaryAmount does not render to JSON very well. This is easily fixed with
    Jackson (de)serializers. You can how money values are rendered to and from JSON in the
    MonetaryAmountSerializer and MonetaryAmountDeserializer classes. They are engaged by
    annotating a property (e.g. price) with the MonetaryAmountJsonSerialize annotation.

  • DatasourceProxyBeanPostProcessor

    The test cases in this project assert the database statements for various situations. Being
    able to assert what statements are executed is key to making sure your model does what it
    is designed to do. It as allows you to find where the model can be improved where otherwise
    it wouldn’t be as obvious. Here are as example of what is possible with the proxy:

  1. Assert.assertThat(proxyDataSource, executionCount(10));
  2. Assert.assertThat(proxyDataSource, insertCount(4));
  3. Assert.assertThat(proxyDataSource, selectCount(1));
  4. Assert.assertThat(proxyDataSource, updateCount(1));
  5. Assert.assertThat(proxyDataSource, deleteCount(4));
  • HAL Browser

    This project includes the HAL Browser to navigate the Hateoas API. I didn’t spent too
    much testing the UI. though. Springfox 2.9.2 does not support Spring Boot 2.1 Hateoas,
    and Springfox 3.0 is not released at the time this is being written.

    There is a test case ShipRestRepositoryTests that invokes the API to add a Cabin to a Ship.

    TODO: Add validation annotations to the entity beans.

  • Hibernate Statistics

    The Spring Actuator can expose Hibernate statistics.

    TODO: Add information to fetch stats.

learn-jpa-hibernate-entity-graphs

How to Recognize and Resolve the N+1 Problem

How to Better Query Data (Criteria API)

Want to know how to recognize the N+1 problem? You just need to be able to easily count
how many queries take place for a given use case and have an expectation for how many
should take place. For example, if you expect one query to take place and find that
thousands are actually taking place, then you should probably investigate your design
to see if are suffering from the N+1 problem.

This project contains a contrived model to accentuate the N+1 problem. The model
consists of students, teachers and courses. Obviously, students enroll in courses and
the courses are taught by teachers. To really cause an N+1 mess, the relationship between
the entities are all LAZY.

The use case is to create a report (CSV file) of all the students and their courses
along with which teacher is teaching the course. Just ignore that fact that we are producing
a report of the entire database. But we will produce the report in a variety of ways
to investigate how many queries get executed:

  • The N+1 Problematic Way
  • Custom Queries
  • Entity Graphs

A test case will show how many queries get executed. The take away from this exercise
is that one should be skilled in asserting how many queries get executed for each test
case, and then knowing the tools to resolve problems.

Knowing that you have options on how data is retrieved, you can resolve and prevent
the N+1 problem in your application.

More information can be found here:

https://vladmihalcea.com/how-to-detect-the-n-plus-one-query-problem-during-testing/

How to Better Control Data with Projections

Another way the N+1 problem manifests itself is by relationships being traversed when
serializing an entity into JSON. In order to not traverse unintended relationships,
one can define projections. A projection is implemented via an interface that specifies
exactly what data should be returned to a client.

This project defines several projections and compares the data returned to a client
to not using a projection.

learn-jpa-hibernate-multiple-datasources

Having multiple data sources also means having multiple entity manager factories and
deciding if one should have multiple transaction managers or a single one with XA support.

This project shows how to set up multiple data sources, one H2 database, one Derby database
with a JTA transaction manager using Narayana.

There are abstract classes, AbstractDataSourceConfiguration and AbstractJpaConfiguration
with re-usable code that one can use to create data sources and entity manager factories.

The TransactionManagerConfiguration class contains instructions to change from the Narayana
transaction manager to dual (but separate) JPA data source transaction managers.

learn-jpa-hibernate-extended-repository

Spring’s ability to dynamically implement @Repository interfaces is super powerful.
But sometimes there is a requirement where the out of box features do not support what
is needed. It is nice to extend what Spring implements. And that is what this
project shows. The key to enabling a new base class for the interface is the
@EnableJpaRepositories annotation. In the extension, one can implement new features, or
change and/or override what Spring provides.

This project implements a new method to query by a property passed into the repository
and perform a like query against of value.

learn-jpa-hibernate-mapped-super-class

Mapped super classes provide a convenient location for modeling common
columns/properties across two or more similar entity beans.

In this silly example, a star schema is used as the model. But as I have
seen many times, developers who want to use JPA where JPA might not be
appropriate, have a database view created to make using JPA easier. So
included in this model is a view that brings together the dimension and
fact tables so that the developer doesn’t need to model any dimension tables.
Since views cannot be updated, an updatable version of the sales entity bean
is created. The two versions of the sales entity share a mapped super class.

learn-jpa-hibernate-3rd-party-classes

Sometimes one may want or must use a Java class that one does not control (as is the case for
third party code). In this situation, one cannot put annotations on the class for them
to become entity beans. Therefore, one needs to resort to specifying the entity beans through
XML configuration, which is historically how JPA was done originally.

In this project, the entity beans do not have any JPA annotations on them, and instead
they are documented by way of persistence.xml. In order to load persistence.xml, one
must build an EntityManagerFactory that loads the file, which is located on the classpath
in /META-INF/persistence.xml.

learn-jpa-hibernate-L2-caching

In JPA, the “Level 1” cache is the entity manager itself. The “Level 2” cache allows
for caching of entities and queries across entity sessions or transactions. In this
project, Hibernate is configured with ehcache capabilities.

The pom.xml file has the extra dependency for hibernate-ehcache and application.yml
file has the Hibernate properties to enable caching for both entities and queries.
The Course entity bean has Hibernate’s Cacheable annotation to enable caching of
courses. The TeacherRepository uses a QueryHint to allow queries to cached.
The ehcache.xml file has the configuration to allow one to carefully manage how
objects are stored in the cached.

learn-jpa-hibernate-batch-operations

JPA batch operations align with JDBC batch operations and try to optimize a long series
of SQL statements that need to be executed by the application.

The application.yml file contains Hibernate properties that enable batching, in this
case 50 records each. The Event entity is the bean that is inserted into the database
in batches. It is important to note that the Event entity bean uses sequences to generate
its Id column, because identity columns are not supported for batch statements.

A potential optimization when dealing with a long list of records is to flush and clear
the entity manager of saved records. This way, the entire list of records does not need
to be stored in memory.

learn-jpa-hibernate-bulk-operations

Bulk operations are those that are performed by the database and not in the application.
At the time of this writing, JPA supports only delete and update statements. JPA does not
support insert statements except for native queries.

This project includes an easy example of performing both the update and delete statements,
but my challenge was to support the insert from select statement where the select statement
is a JPQL statement. The InsertFromSelect class contains a method that accepts a
specification to produce a query and column mappings to produce the insert statement.
The class uses Hibernate internals to produce the native query statement that is still
required to execute the query.

learn-jpa-hibernate-search

Hibernate has integration with Lucene to do searches outside of the database using
an index.

I wanted a project to learn how to build a lucene index and see how to perform
a search. This project has an easy method to search a single table.

learn-jpa-hibernate-blaze

Blaze Persistence is an alternative API to the JPA Criteria API.

This project has a handful of test methods that demonstrate using Blaze Persistence. Blaze
certainly does have a more natural API to building queries based on entity beans.

learn-jpa-hibernate-active-record-aspects

learn-jpa-hibernate-active-record-example

Martin Fowler defines an active record as “an object that wraps a row in a database table or view,
encapsulates the database access, and adds domain logic on that data.” For Spring Data
JPA, the key aspect here is that the database access is encapsulated in the entity bean,
and not using a repository bean.

Some people call the active record pattern an anti-pattern. That won’t be debated
here. These projects, inspired from Spring Roo, merely serve as a curiosity for implementing
the active record in Java using AspectJ.

Consider these two code examples for getting and saving a Person, first as an active record,

  1. Person person = Person.find(Person.class, Long.valueOf(1L));
  2. Person newPerson = new Person("Name");
  3. newPerson.persist();

and then using Spring repositories:

  1. Person person = personRepository.find(Person.class, Long.valueOf(1L));
  2. Person newPerson = new Person("Name");
  3. personRepository.save(newPerson);

The big difference here is the lack of using Spring repositories. It is not saving
that much code, and you lose the ability to mock the repositories. In addition, the
IDE tooling takes some time to get right, so take that into consideration when deciding
to use the active record on your applications. If you ask me, I won’t be using it.

Tooling wise, for Eclipse, install the AspectJ Development Tools.

  1. Warning!!!

Lombok is not compatible with AspectJ at the time of this writing.

learn-jpa-hibernate-swap-in-openjpa

Many times when people say they are using JPA, they are using Hibernate. Even Spring’s
own spring-boot-starter-data-jpa includes Hibernate. But people need to know that
when Spring Data JPA is mentioned, there is the JPA Specification, of which Hibernate
is but one implementation, and Spring is there to make using them so much easier.

But in order for one to say they really know them, one needs to know where the dividing lines
are. And one way to investigate that is by playing with other implementations of JPA.
Two other JPA implementations besides Hibernate are OpenJPA and EclipseLink.

There are two sub-projects in this project that are similar in nature. Each swaps out the
default Hibernate implementation in favor of OpenJPA and EclipseLink respectively.

Notable differences between these and the Hibernate version is the required configuration
class (OpenJpaConfiguration, EclipseLinkConfiguration) to implement a TransactionManager
and EntityManagerFactory. They each have their own properties which one can see in
the application.yml file.

Playing around with the different implementations, one notices small differences. For
example, Hibernate has no problem understanding this query: From Course. However,
EclipseLink wants the query to have an alias like so: From Course c. Finally OpenJPA
wants a statement like this: Select c from Course c.

Hibernate still remains my favorite implementation. OpenJPA is my least favorite because
of the weaving step. (I haven’t found a dynamic configuration that works for me.)

For more information

Here are some links to other great information: