其他分享
首页 > 其他分享> > 【SpringData&JPA从入门到精通】02-JPA API

【SpringData&JPA从入门到精通】02-JPA API

作者:互联网

笔记来源:尚硅谷jpa开发教程全套完整版(初学者零基础入门)

目录

JPA API

1、Persistence

Persistence 类是用于获取 EntityManagerFactory 实例

该类包含一个名为 createEntityManagerFactory 的静态方法,它有如下两个重载方法

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.show_sql", false);
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName, properties);

此时执行 Main 方法,将不会打印 SQL 相关信息

2、EntityManagerFactory

EntityManagerFactory 接口主要用来创建 EntityManager 实例。该接口约定了如下 4 个方法:

测试代码:我们分别在 EntityManagerFactory 实例创建后及关闭 EntityManagerFactory 后打印其 isOpen() 结果

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
System.out.println(entityManagerFactory.isOpen());
// ...
entityManagerFactory.close();
System.out.println(entityManagerFactory.isOpen());

日志信息

true
// ...
false

3、EntityManager

在 JPA 规范中,EntityManager 是完成持久化操作的核心对象。实体作为普通 Java 对象,只有在调用 EntityManager 将其持久化后才会变成持久化对象。EntityManager 对象在一组实体类与底层数据源之间进行 O/R 映射的管理

它可以用来管理和更新 Entity Bean,根据主键查找 Entity Bean,还可以通过 JPQL 语句查询实体

实体的状态:

准备工作

public class JPATest {
    private EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;
    private EntityTransaction entityTransaction;

    @Before
    public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory("jpa-1");
        entityManager = entityManagerFactory.createEntityManager();
        entityTransaction = entityManager.getTransaction();
        entityTransaction.begin();
    }

    @After
    public void destory() {
        entityTransaction.commit();
        entityManager.close();
        entityManagerFactory.close();
    }
}

3.1、find()

find(Class<T> entityClass,Obiect primaryKey):返回指定的 OID 对应的实体类对象

/**
 * 类似于 Hibernate 中 Session 的 get() 方法
 */
@Test
public void testFind() {
    Customer customer = entityManager.find(Customer.class, 2);
    System.out.println(customer.getClass().getName());
    System.out.println("-----------------------------");
    System.out.println(customer);
}

日志信息

Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
com.vectorx.jpa.helloworld.Customer
-----------------------------
Customer{id=2, lastName='Vector2', email='vector2@qq.com', age=100, birthDay=2022-04-10, createTime=2022-04-10 21:06:19}

3.2、getReference()

getReference(Class<T> entityClass, Object primaryKey):与 find() 方法类似,不同的是:

/**
 * 类似于 Hibernate 中 Session 的 load() 方法
 */
@Test
public void testGetReference() {
    Customer customer = entityManager.getReference(Customer.class, 2);
    System.out.println(customer.getClass().getName());
    System.out.println("-----------------------------");
    System.out.println(customer);
}

日志信息

com.vectorx.jpa.helloworld.Customer_$$_javassist_0
-----------------------------
Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
Customer{id=2, lastName='Vector2', email='vector2@qq.com', age=100, birthDay=2022-04-10, createTime=2022-04-10 21:06:19}

1)可以发现,getReference() 方法与 find() 方法的区别:

com.vectorx.jpa.helloworld.Customer
com.vectorx.jpa.helloworld.Customer_$$_javassist_0

这说明 getReference() 方法获取的实体对象只是其 代理对象,只有在真正使用实体对象的属性时,JPA 才会向数据库发送 SQL,初始化实体对象。因此,这就会导致有可能出现 懒加载异常 的问题

@Test
public void testGetReference() {
    Customer customer = entityManager.getReference(Customer.class, 2);
    System.out.println(customer.getClass().getName());
    System.out.println("-----------------------------");
    entityTransaction.commit();
    entityManager.close();
    System.out.println(customer);
}

日志信息:抛出了 LazyInitializationException 异常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
	at com.vectorx.jpa.helloworld.Customer_$$_javassist_0.toString(Customer_$$_javassist_0.java)
	at java.lang.String.valueOf(String.java:2994)
	at java.io.PrintStream.println(PrintStream.java:821)
	at helloworld.JPATest.testGetReference(JPATest.java:54)

2)如果查询不到对应记录

@Test
public void testGetReference() {
    Customer customer = entityManager.getReference(Customer.class, 6);
    System.out.println(customer);
}

日志信息:抛出 EntityNotFoundException 异常

javax.persistence.EntityNotFoundException: Unable to find com.vectorx.jpa.helloworld.Customer with id 6
<5 internal lines>
    at com.vectorx.jpa.helloworld.Customer_$$_javassist_0.toString(Customer_$$_javassist_0.java)
	at java.lang.String.valueOf(String.java:2994)
	at java.io.PrintStream.println(PrintStream.java:821)
	at helloworld.JPATest.testGetReference(JPATest.java:55) <27 internal lines>

3.3、persist()

persist(Object entity):用于将新创建的 Entity 纳入到 EntityManager 的管理。该方法执行后,传入 persist() 方法的 Entity 对象转换成持久化状态

存疑点:不知为何,我后面的测试结果是抛出了 PersistenceException,而不是 EntityExistException

/**
 * 类似于 Hibernate 中 Session 的 save 方法,使对象有临时状态变为持久化状态
 */
@Test
public void testPersistence() {
    Customer customer = new Customer();
    customer.setLastName("Vector4");
    customer.setEmail("vector4@qq.com");
    customer.setAge(4);
    customer.setBirthDay(new Date());
    customer.setCreateTime(new Date());
    entityManager.persist(customer);
    System.out.println(customer.getId());
}

日志信息

Hibernate: 
    insert 
    into
        JPA_CUSTOMERS
        (age, birthDay, createTime, email, LAST_NAME) 
    values
        (?, ?, ?, ?, ?)
4

JPA_CUSTOMERS 表数据插入成功

image-20220410212446625

1)和 Hibernate 中 Session 的 save 方法的不同之处在于:若对象有 id,则不能执行 insert 操作,而会抛出异常

@Test
public void testPersistence() {
    Customer customer = new Customer();
    // ...
    customer.setId(5);
    entityManager.persist(customer);
}

日志信息:抛出 PersistenceException 异常

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.vectorx.jpa.helloworld.Customer
<4 internal lines>
	at helloworld.JPATest.testPersistence(JPATest.java:71) <27 internal lines>
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.vectorx.jpa.helloworld.Customer <27 internal lines>
	... 28 more

3.4、remove()

remove(Object entity):删除实例。如果实例是被管理的,即与数据库实体记录关联,则同时会删除关联的数据库记录

/**
 * 类似于 Hibernate 中 Session 的 delete() 方法。把对象对应的记录从数据库中移除
 */
@Test
public void testRemove() {
    Customer customer = new Customer();
    customer.setId(4);
    entityManager.remove(customer);
}

日志信息:抛出了 IllegalArgumentException 异常,不能移除一个 游离对象

java.lang.IllegalArgumentException: Removing a detached instance com.vectorx.jpa.helloworld.Customer#4
<6 internal lines>
    at helloworld.JPATest.testRemove(JPATest.java:82) <27 internal lines>

1)需要注意的是,该方法只能移除 持久化对象。而 Hibernate 中 Session 的 delete() 方法还可以移除 游离对象

怎么办呢?

@Test
public void testRemove() {
    Customer customer = entityManager.find(Customer.class, 4);
    entityManager.remove(customer);
}

日志信息

Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
Hibernate: 
    delete 
    from
        JPA_CUSTOMERS 
    where
        id=?

JPA_CUSTOMERS 表数据删除成功

image-20220410212551748

3.5、merge()

merge(T entity)merge() 用于处理 Entity 的同步。即数据库的插入和更新操作

image-20220411214427437

1)临时对象

/**
 * 类似于 Hibernate 中 Session 的 saveOrUpdate() 方法
 * 1、临时对象
 * 创建新的对象,将临时对象属性值复制到新对象中,对新对象执行 insert 持久化操作
 * 所以临时对象没有 id,新对象有 id
 */
@Test
public void testMerge1() {
    Customer customer = new Customer();
    customer.setLastName("Vector4");
    customer.setEmail("vector4@qq.com");
    customer.setAge(4);
    customer.setBirthDay(new Date());
    customer.setCreateTime(new Date());
    Customer customer2 = entityManager.merge(customer);
    System.out.println("customer#id: " + customer.getId());
    System.out.println("customer2#id: " + customer2.getId());
}

日志信息

Hibernate: 
    insert 
    into
        JPA_CUSTOMERS
        (age, birthDay, createTime, email, LAST_NAME) 
    values
        (?, ?, ?, ?, ?)
customer#id: null
customer2#id: 6

JPA_CUSTOMER 表数据

image-20220411221058027

2)游离对象

a. EntityManager 缓存中没有该对象 + 数据库中没有对应记录

/**
 * 2、游离对象(即传入的对象有 OID)
 * 2.1、EntityManager 缓存中没有该对象 + 数据库中没有对应记录
 * 创建新的对象,将游离对象属性值复制到新对象中,对新对象执行 insert 持久化操作
 */
@Test
public void testMerge2() {
    Customer customer = new Customer();
    customer.setLastName("Vector4");
    customer.setEmail("vector4@qq.com");
    customer.setAge(4);
    customer.setBirthDay(new Date());
    customer.setCreateTime(new Date());
    customer.setId(100);
    Customer customer2 = entityManager.merge(customer);
    System.out.println("customer#id: " + customer.getId());
    System.out.println("customer2#id: " + customer2.getId());
}

日志信息

Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
Hibernate: 
    insert 
    into
        JPA_CUSTOMERS
        (age, birthDay, createTime, email, LAST_NAME) 
    values
        (?, ?, ?, ?, ?)
customer#id: 100
customer2#id: 7

JPA_CUSTOMER 表数据

image-20220411221517536

b. EntityManager 缓存中没有该对象 + 数据库中有对应记录

/**
 * 2、游离对象(即传入的对象有 OID)
 * 2.2、EntityManager 缓存中没有该对象 + 数据库中有对应记录
 * JPA 查询对应记录并返回一个对象,将游离对象属性值复制到查询对象中,对查询对象执行 update 持久化操作
 */
@Test
public void testMerge3() {
    Customer customer = new Customer();
    customer.setLastName("Vector4");
    customer.setEmail("vector4@qq.com");
    customer.setAge(4);
    customer.setBirthDay(new Date());
    customer.setCreateTime(new Date());
    customer.setId(3);
    Customer customer2 = entityManager.merge(customer);
    System.out.println("customer#id: " + customer.getId());
    System.out.println("customer2#id: " + customer2.getId());
    System.out.println("customer == customer2: " + (customer == customer2));
}

日志信息

Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
customer#id: 3
customer2#id: 3
customer == customer2: false
Hibernate: 
    update
        JPA_CUSTOMERS 
    set
        age=?,
        birthDay=?,
        createTime=?,
        email=?,
        LAST_NAME=? 
    where
        id=?

JPA_CUSTOMER 表数据

image-20220411222551376

c. EntityManager 缓存中有该对象

/**
 * 2、游离对象(即传入的对象有 OID)
 * 2.3、EntityManager 缓存中有该对象
 * JPA 将游离对象属性值复制到 EntityManager 缓存对象中,对 EntityManager 缓存对象执行 update 持久化操作
 */
@Test
public void testMerge4() {
    Customer customer = new Customer();
    customer.setLastName("Vector4");
    customer.setEmail("vector4@qq.com");
    customer.setAge(4);
    customer.setBirthDay(new Date());
    customer.setCreateTime(new Date());
    customer.setId(2);
    Customer customer1 = entityManager.find(Customer.class, 2);
    entityManager.merge(customer);
    System.out.println("customer == customer2: " + (customer == customer2));
}

日志信息

Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
customer == customer2: false
Hibernate: 
    update
        JPA_CUSTOMERS 
    set
        age=?,
        birthDay=?,
        createTime=?,
        email=?,
        LAST_NAME=? 
    where
        id=?

JPA_CUSTOMER 表数据

image-20220411223821319

3.6、其他方法

这里以下列两个方法为例

1)flush()

/**
 * 类似于 Hibernate 中 Session 的 flush 方法
 */
@Test
public void testFlush() {
    Customer customer = entityManager.find(Customer.class, 3);
    System.out.println(customer);
    
    customer.setLastName("flush");
    entityManager.flush();
    
    customer = entityManager.find(Customer.class, 3);
    System.out.println(customer);
}

日志信息

Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
Customer{id=3, lastName='Vector4', email='vector4@qq.com', age=4, birthDay=2022-04-11, createTime=2022-04-11 22:27:19.0}
Hibernate: 
    update
        JPA_CUSTOMERS 
    set
        age=?,
        birthDay=?,
        createTime=?,
        email=?,
        LAST_NAME=? 
    where
        id=?
Customer{id=3, lastName='flush', email='vector4@qq.com', age=4, birthDay=2022-04-11, createTime=2022-04-11 22:27:19.0}

2)refresh()

/**
 * 类似于 Hibernate 中 Session 的 refresh 方法
 */
@Test
public void testRefresh() {
    Customer customer1 = entityManager.find(Customer.class, 1);
    customer1 = entityManager.find(Customer.class, 1);
    System.out.println("----------------------------");
    Customer customer2 = entityManager.find(Customer.class, 2);
    customer2 = entityManager.find(Customer.class, 2);
    entityManager.refresh(customer2);
}

日志信息

Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
----------------------------
Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?
Hibernate: 
    select
        customer0_.id as id1_0_0_,
        customer0_.age as age2_0_0_,
        customer0_.birthDay as birthDay3_0_0_,
        customer0_.createTime as createTi4_0_0_,
        customer0_.email as email5_0_0_,
        customer0_.LAST_NAME as LAST_NAM6_0_0_ 
    from
        JPA_CUSTOMERS customer0_ 
    where
        customer0_.id=?

4、EntityTransaction

EntityTransaction 接口用来管理资源层实体管理器的事务操作。通过调用实体管理器的 getTransaction() 方法获得其实例

总结

本节重点掌握

附上导图,仅供参考

02-JPA API

标签:02,customer,Customer,SpringData,customer0,JPA,_.,id
来源: https://www.cnblogs.com/vectorx/p/16133145.html