根据上一篇文章中涉及到的方法进行相关的测试,这里我们需要准备一些测试的持久化类
package com.os.model; import javax.persistence.*; import java.util.Date; @Entity @Table(name = "jpa_teacher") public class Teacher { private Integer teacherId; private String teacherName; private Integer age; private String sex; private Date birthday; private Date createDate; @Column(name = "teacher_id") @GeneratedValue(strategy = GenerationType.IDENTITY) @Id public Integer getTeacherId() { return teacherId; } public void setTeacherId(Integer teacherId) { this.teacherId = teacherId; } @Column(name = "teacher_name",length = 16,nullable = false) public String getTeacherName() { return teacherName; } public void setTeacherName(String teacherName) { this.teacherName = teacherName; } @Column(length = 3) public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Column(length = 1) public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Temporal(TemporalType.DATE) public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Column(name = "create_date") @Temporal(value = TemporalType.TIMESTAMP) public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } @Override public String toString() { return "Teacher{" + "teacherId=" + teacherId + ", teacherName='" + teacherName + '/'' + ", age=" + age + ", sex='" + sex + '/'' + ", birthday=" + birthday + ", createDate=" + createDate + '}'; } } 复制代码
数据也准备完毕了,使用程序添加的简单数据
引入单元测试,方便比较学习
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> 复制代码
单元测试的基本模版代码如下
package com.os.test; import org.junit.After; import org.junit.Before; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class JPATest { private EntityManagerFactory factory ; private EntityManager entityManager ; private EntityTransaction tx; @Before public void init(){ factory = Persistence.createEntityManagerFactory("jpa02"); entityManager = factory.createEntityManager(); tx = entityManager.getTransaction(); tx.begin(); } @After public void close(){ tx.commit(); entityManager.close(); factory.close(); } } 复制代码
find (Class<T> entityClass,Object primaryKey)
:返回指定的 OID 对应的实体类对象,如果这个实体存在于当前的持久化环境,则返回一个被缓存的对象;否则会创建一个新的 Entity, 并加载数据库中相关信息;若 OID 不存在于数据库中,则返回一个 null。第一个参数为被查询的实体类类型,第二个参数为待查找实体的主键值。( 类似于Hibernate中的get方法 )
之后的版本,我们就不在设置粘贴模版代码了,代码如下:
package com.os.test; import com.os.model.Teacher; import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class JPATest { private EntityManagerFactory factory ; private EntityManager entityManager ; private EntityTransaction tx; @Before public void init(){ factory = Persistence.createEntityManagerFactory("jpa02"); entityManager = factory.createEntityManager(); tx = entityManager.getTransaction(); tx.begin(); } @After public void close(){ tx.commit(); entityManager.close(); factory.close(); } //类似于 hibernate 中 Session 的 get 方法. @Test public void testFind01(){ Teacher teacher = entityManager.find(Teacher.class,1);//该ID是数据库存在 System.out.println("========================="); System.out.println(teacher); } @Test public void testFind02(){ Teacher teacher = entityManager.find(Teacher.class,100);//该ID是数据库不存在 System.out.println("========================="); System.out.println(teacher); } } 复制代码
getReference (Class<T> entityClass,Object primaryKey)
:与find()方法类似,不同的是:如果缓存中不存在指定的 Entity, EntityManager 会创建一个 Entity 类的代理,但是不会立即加载数据库中的信息,只有 第一次真正使用 此 Entity 的属性才加载,所以如果此 OID 在数据库不存在, getReference() 不会返回 null 值, 而是抛出EntityNotFoundException ( 类似于Hibernate中的load方法 )
//类似于 hibernate 中 Session 的 load 方法 @Test public void testGetReference01(){ Teacher teacher = entityManager.getReference(Teacher.class,1);//该ID是数据库存在 System.out.println("========================="); System.out.println(teacher); } /** * javax.persistence.EntityNotFoundException: Unable to find com.os.model.Teacher with id 100 */ @Test public void testGetReference02(){ Teacher teacher = entityManager.getReference(Teacher.class,100);//该ID是数据库存在 System.out.println("========================="); System.out.println(teacher); } /** * org.hibernate.LazyInitializationException: could not initialize proxy [com.os.model.Teacher#1] - no Session */ @Test public void testGetReference03(){ Teacher teacher = entityManager.getReference(Teacher.class,1);//该ID是数据库存在 System.out.println("========================="); tx.commit(); entityManager.close(); System.out.println(teacher); } 复制代码
getReference涉及到延迟加载,需要注意EntityManager没有被关闭
为什么使用延迟加载?大家可以执行百度
persist (Object entity)
:用于将新创建的Entity纳入到EntityManager的管理。该方法执行后,传入 persist()
方法的 Entity 对象转换成持久化状态。(类似于Hibernate中的save方法)
如果传入 persist() 方法的 Entity 对象已经处于持久化状态,则 persist() 方法什么都不做。
//类似于 hibernate 的 save 方法. 使对象由临时状态变为持久化状态. //和 hibernate 的 save 方法的不同之处: 若对象有 id, 则不能执行 insert 操作, 而会抛出异常. @Test public void testPersist01(){ Teacher teacher = new Teacher(); teacher.setTeacherName("唐僧"); teacher.setAge(99); teacher.setSex("女"); teacher.setBirthday(new Date()); teacher.setCreateDate(new Date()); entityManager.persist(teacher);//teacher已经处于持久化状态 entityManager.persist(teacher); entityManager.persist(teacher); System.out.println(teacher.getTeacherId()); } 复制代码
上述代码说明:我们执行了三次的保存操作,但是我们实际上添加到数据库中记录数为一条,原因就是执行persist方法后,该teacher对象已经处于了持久化状态(在一级缓存中),再次执行 entityManager.persist(teacher);
在一级缓存看看是否存在,如果一致,那么不不执行任何操作
//类似于 hibernate 的 save 方法. 使对象由临时状态变为持久化状态. //和 hibernate 的 save 方法的不同之处: 若对象有 id, 则不能执行 insert 操作, 而会抛出异常. @Test public void testPersist02(){ Teacher teacher = new Teacher(); teacher.setTeacherName("沙僧"); teacher.setAge(99); teacher.setSex("男"); teacher.setBirthday(new Date()); teacher.setCreateDate(new Date()); entityManager.persist(teacher);//teacher已经处于持久化状态 teacher.setTeacherName("卷帘大将"); System.out.println(teacher.getTeacherId()); } 复制代码
上述代码说明:在事务提交之前,检查一级缓存中存储的对象和实际的对象是否一致,如果不一致会产生Update语句,很重要的
//类似于 hibernate 的 save 方法. 使对象由临时状态变为持久化状态. //和 hibernate 的 save 方法的不同之处: 若对象有 id, 则不能执行 insert 操作, 而会抛出异常. /* * javax.persistence.PersistenceException: * org.hibernate.PersistentObjectException: * detached entity passed to persist: com.os.model.Teacher * */ @Test public void testPersist03(){ Teacher teacher = new Teacher(); teacher.setTeacherName("悟空"); teacher.setAge(99); teacher.setSex("男"); teacher.setBirthday(new Date()); teacher.setCreateDate(new Date()); teacher.setTeacherId(88);//注意我设置了主键ID entityManager.persist(teacher);//teacher已经处于持久化状态 System.out.println(teacher.getTeacherId()); } 复制代码
如果对删除状态的 Entity 进行 persist() 操作,会转换为持久化状态。
@Test public void testPersist04(){ Teacher teacher = entityManager.find(Teacher.class,5);//1.持久化状态 entityManager.remove(teacher); System.out.println("teacher = " + teacher);//2.处于删除状态 entityManager.persist(teacher);//3.处于游离状态 } 复制代码
上述代码说明:其实根本就没有产生delete语句,只有一个查询操作,因为上述代码给人的感觉“ 还原 ”
如果对游离状态的实体执行 persist() 操作,可能会在 persist() 方法抛出 EntityExistException(也有可能是在flush或事务提交后抛出)。
@Test public void testPersist05(){ Teacher teacher = entityManager.find(Teacher.class,5);//1.持久化状状态 tx.commit(); entityManager.close(); System.out.println("teacher = " + teacher);//2.处于游离状态 entityManager = factory.createEntityManager(); tx = entityManager.getTransaction(); tx.begin(); entityManager.persist(teacher); /* *javax.persistence.PersistenceException: * org.hibernate.PersistentObjectException: * detached entity passed to persist: com.os.model.Teacher * */ } 复制代码
remove (Object entity)
:删除实例。如果实例是被管理的,即与数据库实体记录关联,则同时会删除关联的数据库记录。(类似于Hibernate中的Delete方法)
//类似于 hibernate 中 Session 的 delete 方法. 把对象对应的记录从数据库中移除 //但注意: 该方法只能移除 持久化 对象. 而 hibernate 的 delete 方法实际上还可以移除 游离对象. @Test public void testRemove01(){ Teacher teacher = new Teacher();//瞬时状态 teacher.setTeacherId(4);//数据库中存在该条记录 entityManager.remove(teacher); /* * java.lang.IllegalArgumentException: * Removing a detached instance com.os.model.Teacher#4 * */ } 复制代码
//类似于 hibernate 中 Session 的 delete 方法. 把对象对应的记录从数据库中移除 //但注意: 该方法只能移除 持久化 对象. 而 hibernate 的 delete 方法实际上还可以移除 游离对象. @Test public void testRemove02(){ Teacher teacher = entityManager.getReference(Teacher.class,4);//持久化对象 entityManager.remove(teacher);//使用的时候先查询后执行删除操作 } 复制代码
merge (T entity)
:merge() 用于处理 Entity 的同步。即数据库的插入和更新操作,这个操作的情况有点多,我们通过代码进行说明
/* * 若传入的是一个临时对象 * 会创建一个新的对象, 把临时对象的属性复制到新的对象中, 然后对新的对象执行持久化操作. 所以 * 新的对象中有 id, 但以前的临时对象中没有 id. * */ @Test public void testMerge1(){ Teacher teacher = new Teacher(); teacher.setTeacherName("林黛玉"); teacher.setAge(19); teacher.setSex("女"); teacher.setBirthday(new Date()); teacher.setCreateDate(new Date()); Teacher teacher1 = entityManager.merge(teacher); System.out.println("teacher.getTeacherId() = " + teacher.getTeacherId()); System.out.println("teacher1.getTeacherId() = " + teacher1.getTeacherId()); } 复制代码
@Test public void testMerge2(){ Teacher teacher = new Teacher(); teacher.setTeacherName("林黛玉"); teacher.setAge(19); teacher.setSex("女"); teacher.setBirthday(new Date()); teacher.setCreateDate(new Date()); teacher.setTeacherId(100);//数据库没有该主键ID Teacher teacher1 = entityManager.merge(teacher); System.out.println("teacher.getTeacherId() = " + teacher.getTeacherId()); System.out.println("teacher1.getTeacherId() = " + teacher1.getTeacherId()); } 复制代码
@Test public void testMerge3(){ Teacher teacher = new Teacher(); teacher.setTeacherName("林黛玉"); teacher.setAge(19); teacher.setSex("女"); teacher.setBirthday(new Date()); teacher.setCreateDate(new Date()); teacher.setTeacherId(5);//数据库有该主键ID Teacher teacher1 = entityManager.merge(teacher); System.out.println("teacher.getTeacherId() = " + teacher.getTeacherId()); System.out.println("teacher1.getTeacherId() = " + teacher1.getTeacherId()); } 复制代码
@Test public void testMerge4(){ Teacher teacher = new Teacher(); teacher.setTeacherName("林黛玉"); teacher.setAge(19); teacher.setSex("女"); teacher.setBirthday(new Date()); teacher.setCreateDate(new Date()); teacher.setTeacherId(7);//数据库有该主键ID System.out.println("teacher = " + teacher); Teacher teacher1 = entityManager.find(Teacher.class,7);//一级缓存中存在该对象 System.out.println("teacher1 = " + teacher1); entityManager.merge(teacher); System.out.println(teacher==teacher1);//返回的是false } 复制代码
flush ()
:同步持久上下文环境,即将持久上下文环境的所有未保存实体的状态信息保存到数据库中
这里需要使用断点调试,断点设置如图
@Test public void testFlush(){ Teacher teacher = entityManager.find(Teacher.class,1); System.out.println("teacher = " + teacher); teacher.setTeacherName("林冲"); entityManager.flush(); } 复制代码
refresh (Object entity)
:用数据库实体记录的值更新实体对象的状态,即更新实例的属性值。
@Test public void testReflush(){ Teacher teacher = entityManager.find(Teacher.class,1); System.out.println("teacher = " + teacher); teacher = entityManager.find(Teacher.class,1); entityManager.refresh(teacher);//重新进行查询操作 } 复制代码