The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › JPA
What is an entity, and how does it differ from an ordinary class?
An entity is a Java class that is paired with a database table, and one object of it is paired with one row of the table. In code, it is an ordinary Java class declared with class, and it differs from an ordinary class in two places. @Entity above the class is a marker that objects of this class are stored in a table, and @Id above a field is a marker that this field is the primary key (the column that tells rows apart). With these two, JPA (Jakarta Persistence, here Hibernate) looks at the fields of the class and pairs them with the columns of the table, and when you pass an object to em.persist, it builds the INSERT statement for you and runs it at commit. We do not write SQL. Here, em is the EntityManager object that makes JPA do the saving. In this lab, you remove the two markers one at a time and run the same saving code, to see whether the table is created and whether an INSERT statement is sent.
Checked against real execution · Compiled the source as it is for all 8 combinations on Hibernate 7.4.5 and H2 2.4.240, really started JPA, saved, and checked against the results
// Marker: objects of this class are stored as one row of a table
@Entity
public class Member {
// Marker: this field is the primary key
@Id
private Long id;
private String name;
protected Member() { }
public Member(Long id, String name) {
this.id = id;
this.name = name;
}
}
// The side that saves
em.getTransaction().begin();
em.persist(new Member(1L, "Alice"));
em.getTransaction().commit();
This was checked against real execution on Hibernate 7.4.5 and H2 2.4.240 (an in-memory database). Spring was not used, and Hibernate was started directly in code (the class was registered in Configuration, without persistence.xml). For all 8 combinations, the same text as the Member source on the screen (with only the package and import lines added) was compiled, and a new Java process was started each time. In the combinations without @Entity, Member was registered in the same way. The three "side that saves" lines on the screen are actually code inside main, and the line that gets the EntityManager (em), the line that catches and records the exception, and the lines that measure were left out of the screen. What was checked is whether JPA fails while starting and the kind of exception, the tables and columns in H2 right after starting and after the run (INFORMATION_SCHEMA.COLUMNS), the number and text of the INSERT statements captured with a StatementInspector (when the persist line ended and when the commit line ended), and the number of rows and the content of the table after the run. H2 stores the table name as MEMBER and the column names as ID, NAME, and EMAIL, and the screen shows the table name with only the first letter capitalized and the column names in lowercase to make them easier to read. The columns were not created in the order in which the fields are written (in this run the order was id, email, name). The rule that decides the order was not checked. What the documentation defines is section 2.1 of the Jakarta Persistence 3.2 specification (an entity class must have @Entity, must have a public or protected constructor with no arguments, and must not be final) and section 2.4 (every entity must have a primary key, and a simple primary key is declared by putting @Id on a field), and items 3.4.1, 3.4.3, 3.4.5, and 3.4.6 of section 3.4 (Entity types) of the Hibernate ORM 7.0 User Guide (the table name follows the entity name by default, and putting @Id on a field makes it field access). These documents were opened with WebFetch, and what came back was a summary, not the original text, so I could not check each sentence against the original. For the specification, only the first part was read (the first 100,000 characters, which contain sections 2.1 and 2.4). The following are not what the documentation defines but behaviors observed on this version. When a class without @Entity is registered, JPA finishes starting without an error (there is no entity that JPA knows), and em.persist throws an IllegalArgumentException, and the result is the same even if @Id is there. With @Entity but without @Id, an AnnotationException is thrown when starting and no table is made (item 3.4.5 of the Hibernate 7.0 User Guide says that omitting the identifier used to be allowed but is deprecated, but on 7.4.5 it was an error). The table is created not at persist or commit but when JPA starts (with the setting hibernate.hbm2ddl.auto=create-drop), and the INSERT statement was sent not on the persist line but on the commit line. The statement has the shape insert into Member (name,id) values (?,?), its text may differ by Hibernate version, and details such as whether that INSERT is sent at persist or at commit are covered in the "Persistence context" lab. What the code on the screen leaves out is the package and import lines, and only the fields id, name, and email were covered. @Table and @Column, which change the pairing of names and columns, @GeneratedValue, which makes primary key values automatically, accessor methods, and the rest of the conditions on an entity class (it must not be final, and so on) were not covered. It was not checked against execution on MySQL.
Previous lab: Test code · Next lab: Persistence context
Struck-through text was removed from the first version of the code; highlighted text was added.