“This is the 20th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
JPA overview
JPA, short for Java Persistence API, is a JDK 5.0 annotation or XML mapping describing object-relational tables and persisting run-time entity objects to a database. Sun introduced the new JPA ORM specification for two reasons: first, to simplify the development of existing Java EE and Java SE applications; Second, Sun wants to integrate ORM technology to make the world one.
An introduction to case
Before we begin, let’s write an introductory case using JPA. Create a JPA Project in Eclipse:JPA version is 2.0. After the project is created, the pilot into the project JAR package, here we use HIbernate as the implementation product of JPA, so import HIbernate JAR package, JPA JAR package and MySQL database driver. Then create the persistent class Customer in the SRC directory:
package com.wwj.jpa.helloworld;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Table(name = "JPA_CUSTOMERS")
@Entity
public class Customer {
private Integer id;
private String lastName;
private String email;
private Integer age;
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
public Integer getId(a) {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "LAST_NAME")
public String getLastName(a) {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail(a) {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge(a) {
return age;
}
public void setAge(Integer age) {
this.age = age; }}Copy the code
Next we open the persistence. XML file in the meta-INF directory, which is the JPA configuration file, and configure it as follows:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="jpa_demo" transaction-type="RESOURCE_LOCAL">
<! Hibernate is the implementation product of JPA. Hibernate is the implementation product of JPA. Hibernate is the implementation product of JPA.
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<! Add persistent class -->
<class>com.wwj.jpa.helloworld.Customer</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<! Configure the basic properties of the JPA implementation product
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
Copy the code
Finally, write the test code:
package com.wwj.jpa.helloworld;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class Main {
public static void main(String[] args) {
// create EntityManagerFactory
EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa_demo");
// create EntityManager
EntityManager manager = factory.createEntityManager();
// start transaction
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
// Make it persistent
Customer customer = new Customer();
customer.setAge(20);
customer.setEmail("[email protected]");
customer.setLastName("zhangsan");
manager.persist(customer);
//5
transaction.commit();
//6. Release resourcesmanager.close(); factory.close(); }}Copy the code
If you have a Hibernate base, you’ll see that JPA is implemented just like Hibernate. You get the factory instance, get the EntityManager from the factory, start the transaction, persist it, commit the transaction, and release the resource. We run the test code and query the table:At this point the introductory case is written.
The basic annotation
The above example uses some basic notes, let me introduce them one by one.
- @Entity: This annotation is used before the Entity class declaration statement to indicate that the Java class is an Entity class and map the Entity class to the data table. If you declare a Customer class, it maps to the Customer table in the database
- @TABLE: When the Entity class has a different name from the database Table it maps to, use the @TABLE annotation. This annotation is used alongside the @Entity annotation, before the Entity class declaration statement, on a separate line, or in line with the declaration statement. The common attribute of the @table annotation is name, which is used to specify the database Table name for the mapping
- @ID: This annotation is used to declare that the attribute of an entity class is mapped to the primary key column of the database. The attribute is usually preceded by the attribute declaration statement, either on a line with the declaration statement or on a separate line. The @ID can also precede the getter method of the attribute
- @GeneratedValue: This annotation is used to declare a primary key generation strategy, specified by the Strategy attribute. By default, JPA automatically selects a primary key generation strategy that best suits the underlying database: SqlServer for Identity and MySQL for Auto Increment. The Strategy attribute provides several alternative strategies.
1 IDENTITY: add the primary key field by using the database ID auto-growth method. Note: Oracle does not support this method. 1 AUTO: JPA automatically selects the appropriate policy. MySQL does not support TABLE: primary keys are generated from tables. The framework generates primary keys from TABLE simulation sequences. Using this policy can make applications easier to migrate to databases
- @basic: This annotation represents a simple attribute mapping to the field of a database table. For getXXX() methods without any annotations, the default annotation is @basic. For example, in the above case, the email and age attributes are not annotated, so the default annotation is @basic
- @column: When the attribute of an entity class has a different name than the Column of the database table it maps to, the @column annotation is required. This annotation usually precedes the attribute declaration statement of the entity class, and can also be used with the @ID annotation. The common attribute of the @column annotation is name, which is used to set the Column name of the mapped database table. The annotation also contains other attributes such as Nullable, Length, and unique
@ Transient annotations
There are specific scenarios, such as adding a utility method to an entity class that provides information about the entity class. As mentioned earlier, JPA will default to @BASIC annotations for attributes that are not annotated in the entity class, so the utility methods will also be mapped to the database table, but obviously we don’t want that, so we need to use the @TRANSIENT annotation.
@Transient
public String getMessage(a) {
return "lastname:" + lastName + "age" + age;
}
Copy the code
This annotation indicates that the attribute is not an attribute that needs to be mapped to a database table and will be ignored by the ORM framework. So it is important to note that if a property does not need to be mapped to a database table, it must be annotated as @TRANSIENT. If not annotated, JPA will add the @BASIC annotation by default.
@ Temporal annotation
Sometimes you need to map a user’s birthday as an attribute to a database table, so you add a birthday attribute of type Date to the Customer class. But when you run it, you’ll see that the birthday column for the table is of type datetime. We know that datetime is a value containing date and time information, while birthday is just a date and does not require a time. How can we change the type of the mapped column? We need to use the @Temporal annotation.
@Temporal(TemporalType.Date)
public Date getBirthday(a) {
return birthday;
}
Copy the code
This annotation allows you to adjust the precision of the Date type during attribute mapping.
This is the end of JPA annotations, I believe you did not see the screen before it, it does not matter, let’s continue to in-depth understanding of JPA API.
Persistence
Persistence class is used to obtain the EntityManagerFactory instance once, this class contains a static method called createEntityManagerFactory. Two overloaded createEntityManagerFactory method is as follows:
- A method that takes one parameter, the name of the persistence unit in persistence.xml
The unit name can be arbitrary, and the previous example used such a fetching method to get an EntityManagerFactory object
- A method that takes two parameters, the first parameter is also the persistence. XML persistence unit name, and the second parameter is a Map type used to set JPA properties. If properties are set through the Map collection, JPA ignores properties set elsewhere. The object property names stored in the Map collection must be the property names of the namespace conventions of the JPA implementation library provider
Map<String,Object> properties = new HashMap<String,Object>();
properties.put("hibernate.show_sql".false);
EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa_demo", properties);
Copy the code
The EntityManagerFactory object can also be obtained in this way. We run the program, and the program works fine, and no SQL statement output is found in the console, indicating that the attribute configuration we added to the Map collection has taken effect
EntityManagerFactory
EntityManagerFactory is similar to SessionFactory in Hibernate. This interface defines the following methods:
- CreateEntityManager () : This method is used to create an instance of an entity manager object
- EntityManager(Map Map) : this method is used to create overloaded methods of EntityManager object instances, and the Map parameter is used to provide EntityManager properties
- IsOpen () : this method is used to check if the EntityManagerFactory isOpen. In fact, the EntityManagerFactory is always open after creation unless the close() method is called to close it
- Close () : This method is used to close the EntityManagerFactory. When the EntityManagerFactory is closed, all resources are freed. Calling isOpen() returns false
EntityManager
The EntityManager class’s methods are very simple and can be learned at a glance if you have Hibernate basics, so I’ll demonstrate them directly in code. The find () method
@Test
public void testFind(a) {
Customer customer = entityManager.find(Customer.class,1);
System.out.println(customer);
}
Copy the code
Running results:
Customer [id=1, lastName=zhangsan, [email protected], age=20, birthday=2019-10-03]
Copy the code
This method is similar to the get() method of a Session object in Hibernate, getReference()
@Test
public void testGetReference(a) {
Customer customer = entityManager.getReference(Customer.class,1);
System.out.println(customer);
}
Copy the code
Running results:
Customer [id=1, lastName=zhangsan, [email protected], age=20, birthday=2019-10-03]
Copy the code
The getReference() method obtains a proxy object and sends an SQL statement only if the object is actually used. The getReference() method is similar to the Load () method of the Session object in Hibernate. Closing EntityManager before using the object throws a lazy load exception. Persist () method
@Test
public void testPersist(a) {
Customer customer = new Customer();
customer.setAge(20);
customer.setBirthday(new Date());
customer.setEmail("[email protected]");
customer.setLastName("lisi");
entityManager.persist(customer);
}
Copy the code
Query database table after run:This method is similar to the Save () method on the Session object in Hibernate and changes the object from transient to persistent. The difference is that if you set an id attribute to an object, persist() will throw an exception, while save() will not.Remove () method
@Test
public void testRemove(a) {
Customer customer = entityManager.find(Customer.class, 2);
entityManager.remove(customer);
}
Copy the code
Query data table after run:This method is similar to Hibernate’s delete() method for Session objects, but unlike delete(), remove() can only delete persistent objects, so the delete operation above requires the find() method to obtain the object to be deleted before deleting it.
Merge () the merge() method is a bit more complicated. Let’s take a closer look at the first case:
@Test
public void testMerge(a) {
Customer customer = new Customer();
customer.setAge(20);
customer.setBirthday(new Date());
customer.setEmail("[email protected]");
customer.setLastName("wangwu");
Customer cst = entityManager.merge(customer);
System.out.println(customer);
System.out.println(cst);
}
Copy the code
Running results:
Customer [id=null, lastName=wangwu, [email protected], age=20, birthday=Thu Oct 03 21:29:20 CST 2019]
Customer [id=3, lastName=wangwu, [email protected], age=20, birthday=Thu Oct 03 21:29:20 CST 2019]
Copy the code
In this program, JPA creates a new object, copies the attributes of the temporary object into the new object, and then persists the new object, so the new object has an ID, but the previous temporary object does not.
Let’s look at the second case:
@Test
public void testMerge2(a) {
Customer customer = new Customer();
customer.setAge(20);
customer.setBirthday(new Date());
customer.setEmail("[email protected]");
customer.setLastName("zhaoliu");
// Set the id attribute
customer.setId(1024);
Customer cst = entityManager.merge(customer);
System.out.println(customer);
System.out.println(cst);
}
Copy the code
Running results:
Customer [id=1024, lastName=zhaoliu, [email protected], age=20, birthday=Thu Oct 03 21:35:07 CST 2019]
Customer [id=4, lastName=zhaoliu, [email protected], age=20, birthday=Thu Oct 03 21:35:07 CST 2019]
Copy the code
In this program, we create a floating object because it has an ID but is not yet associated with the database, and persist it in three different ways. The first case:
- If the object is not in the EntityManager cache,
- If there is no corresponding record in the database
- JPA creates a new object and copies the properties of the current floating object into the new object
- Persisting the newly created object
The second case:
- If the object is not in the EntityManager cache,
- If there is a corresponding record in the database
- JPA queries the corresponding record, returns the corresponding object for that record, and finally copies the properties of the floating object into the returned object
- Persist the returned object
The third case:
- If the object is in the EntityManager cache,
- JPA copies the properties of the floating object into the cache object
- Persistency operations are performed on cached objects
There are also a few less important EntityManager methods that are listed here rather than being shown in code:
- Flush () : This method is used to synchronize the persistent context, that is, to save the state information of all unsaved entities in the persistent context to the database
- SetFlushMode () : Sets Flush mode for the persistence context
- GetFlushMode () : Gets Flush mode for the persistence context and returns the enumeration of the class FlushModeType
- Refresh () : Updates the state of entity objects with values recorded by database entities
- Clear () : Clears the persistence context, disconnects all associated entities, and revokes any uncommitted updates
- Contains () : Determines whether an instance belongs to an entity managed by the current context
EntityTransaction
MySQL, JDBC, Hibernate, etc. MySQL, JDBC, Hibernate, etc.
- Begin () : Used to start a transaction, after which multiple database operations are committed or undone as a whole, or to throw an exception if the transaction has already started
- Commit () : Commit the current transaction, that is, persist all database update operations after the transaction starts to the database
- Rollback () : used to rollback the current transaction. That is, to undo all database updates since the transaction started without affecting the database
- SetRollbackOnly () : Enables the current transaction to be rolled back only
- GetRollbackOnly () : checks whether the rollback only flag is set for the current transaction
- IsActive () : checks whether the current transaction isActive. If true is returned, the begin() method cannot be called, otherwise an exception will be thrown; If false is returned, methods such as commit(), rollback(), setRollbackOnly(), and getRollbackOnly() cannot be called, otherwise exceptions will be thrown
Program source code
Github.com/blizzawang/…