JPA的实体具有四种状态,如图所示:
-
新实体(new)。Entity由应用产生,和EJB3 Persistence运行环境没有联系,也没有唯一的标示符(Identity)。
-
持久化实体(managed)。新实体和EJB3 Persistence运行环境产生关联(通过persist(), merge()等方法),在EJB3 Persistence运行环境中存在和被管理,标志是在EJB3 Persistence运行环境中有一个唯一的标示(Identity)。
-
分离的实体(detached)。Entity有唯一标示符,但它的标示符不被EJB3 Persistence运行环境管理, 同样的该Entity也不被EJB3 Persistence运行环境管理。
-
删除的实体(removed)。Entity被remove()方法删除,对应的纪录将会在当前事务提交的时候从数据库中删除。
接下来动手测试下实体状态:
@Entity
public class Parent {
@Id @GeneratedValue
private int id;
//定义了5中不同的联级类型,all表示包含四种类型
@OneToOne(cascade=CascadeType.PERSIST)
private Child persist;
@OneToOne(cascade=CascadeType.REMOVE)
private Child remove;
@OneToOne(cascade=CascadeType.MERGE)
private Child merge;
@OneToOne(cascade=CascadeType.REFRESH)
private Child refresh;
@OneToOne(cascade=CascadeType.ALL)
private Child all;
// getter and setter
}
@Entity
public class Child {
@Id @GeneratedValue
private int id;
private String name;
public Child(String name) {
this.name = name;
}
public Child() {}
// getter and setter
}
public class Test_CascadeType {
private static EntityManagerFactory fac;
private EntityManager manager;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
fac = Persistence.createEntityManagerFactory("test");
}
@Before
public void setUp() throws Exception {
manager = fac.createEntityManager();
}
@Test
public void persist() {
Parent parent = new Parent();
Child persist = new Child("persist");
Child remove = new Child("remove");
Child merge = new Child("merge");
Child refresh = new Child("refresh");
Child all = new Child("all");
parent.setAll(all);
parent.setMerge(merge);
parent.setPersist(persist);
parent.setRefresh(refresh);
parent.setRemove(remove);
/*
// 这部分代码愿意是直接持久化parent对象,提交时会抛出RollbackException,但当提交第二个事务时则会抛出异常
// org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
// 据说解决方式是设置Parent的主键为非自增,暂时留在,请大牛们指教
manager.getTransaction().begin();
try {
// 抛出异常,因为Child对象merge、remove、refresh的CascadeType未声明为persist类型,只能手动持久化
manager.persist(parent);
manager.getTransaction().commit();
Assert.assertTrue(false);
} catch (Exception e) {
if(manager.getTransaction().isActive())
manager.getTransaction().rollback();
Assert.assertTrue(e instanceof RollbackException);
}
Assert.assertTrue(manager.contains(parent));
*/
manager.getTransaction().begin();
// insert顺序是merge,refresh,remove,all,persist,parent,如果先持久化parent,则先insert parent,最后在update parent的外键值
manager.persist(parent.getMerge());
manager.persist(parent.getRefresh());
manager.persist(parent.getRemove());
manager.persist(parent);
manager.getTransaction().commit();
Query query = manager.createQuery("select o from Child o");
List list = query.getResultList();
Assert.assertEquals(5, list.size());
}
@Test
public void merge() {
Parent parent = manager.find(Parent.class, 1);
Assert.assertEquals("persist", parent.getPersist().getName());// 其余同理
// Clear the persistence context, causing all managed entities to become detached.
// 将Entity能脱离EntityManager,避免长时间保持EntityManager打开占用资源并可以在不同的JVM之间传递Entity。
manager.clear();
parent.getMerge().setName("new merge");
parent.getPersist().setName("new persist");
// Merge the state of the given entity into the current persistence context.
// return the instance that the state was merged to.
Parent mp = manager.merge(parent);
Assert.assertNotSame(mp, parent);
Assert.assertEquals("new persist", parent.getPersist().getName());// 同refresh、remove
Assert.assertEquals("persist", mp.getPersist().getName());
Assert.assertEquals("new merge", parent.getMerge().getName()); // 同all
Assert.assertEquals("new merge", mp.getMerge().getName());
manager.getTransaction().begin();
// manager.persist(parent); // 将抛出PersistenceObjectException:detached entity passed to persist
manager.persist(mp); //或者manager.merge(parent);必须commit才更新到数据库,此处persist等child对象已存在数据库中,故而无需再持久化
manager.getTransaction().commit();
}
@Test
public void refresh() {
// 从数据库中获得实体
Parent p1 = manager.find(Parent.class, 1);
// 其他程序修改了数据库中的值
modifyBYOther();
// 缓存中的何真正要处理的值有所出入,是'脏'数据
Assert.assertEquals("persist", p1.getPersist().getName());
Assert.assertEquals("refresh", p1.getRefresh().getName());
// 用refresh从数据库中获取最新的实体
manager.refresh(p1);
// 验证
Assert.assertEquals("persist", p1.getPersist().getName());
Assert.assertEquals("new", p1.getRefresh().getName());
}
@Test
public void remove() {
Parent parent = manager.find(Parent.class, 1);
manager.getTransaction().begin();
manager.remove(parent);
manager.getTransaction().commit();
Assert.assertNotNull(parent);
Assert.assertNull(manager.find(Parent.class, 1));
Query query = manager.createQuery("select o from Child o");
List list = query.getResultList();
Assert.assertEquals(3, list.size());
}
private void modifyBYOther() {
manager.getTransaction().begin();
Query query = manager.createQuery("update Child o set o.name = 'new'");
query.executeUpdate();
manager.getTransaction().commit();
}
@After
public void tearDown() throws Exception {
manager.close();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
fac.close();
}
}
分享到:
相关推荐
虽然持久化实体的状态在ORM中是一个老生常谈的问题,但是说实在的,我们在开发过程中真的不太在意实体的状态。在Web一般情况下也都是交给Spring去管理实体管理器(EntityManager),所以我们还是有必要啰嗦一下,...
jpa--6.api(EntityManager实体的状态)jpa--6.api(EntityManager实体的状态)jpa--6.api(EntityManager实体的状态)jpa--6.api(EntityManager实体的状态)
生成JPA的实体,带annotation,包括@Entity,@Table(name=xx),@Id,@GeneratedValue,@Column(name=xx) 输出表和字段的comment,包含字段的类型长度 自动生成包名
JPA实体映射对时间字段的处理,使用的JPA比较流行
的第五部分,介绍在 OpenJPA 中如何自动生成实体的唯一标识,包括使用容器自动生成实体标识,借助于数据库的自动编号、序列号、数据库表等技术自动生成实体标识等,并且通过简单的例子描述了这几种情况下的操作过程...
这个主要是和我发的博客的实例,但是博客的时候不知道怎么上传源码,只能单独保存了
struts2 spring jpa操作数据库 级联数据 hibernate
JPA实体bean配置,jpa增删改api,jpasql增删改.pdf
JPA实体bean配置,jpa增删改api,jpasql增删改.doc
JPA视频教程_使用jpa映射单个实体对象
使用JPA的二级缓存的具体实现步骤
jpa--2.持久化操作jpa--2.持久化操作jpa--2.持久化操作jpa--2.持久化操作jpa--2.持久化操作jpa--2.持久化操作jpa--2.持久化操作
springboot jpa 自动生成实体类的 文件 可以拿走直接用 Generate POJOs.groovy
JPA访问状态(Access Mode)字段和属性及其混合访问的demo,再测试时如果出现问题,可以修改自动创建的数据表的主键为auto_increment。
Spring Data JPA系列5:让IDEA自动帮你写JPA实体定义代码.doc
在JPA 之前,Java EE 应用程序将持续类表示为容器管理的实体bean 。使用JPA,您可以将 任何普通的旧式Java 对象(POJO) 类指定为JPA 实体:一个应使用JPA 持续性提供程序的 服务将其非临时字段持久保存到关系数据库...
JPA教程JPA教程JPA教程JPA教程JPA教程
jpa jpa规范 jpa源码 jpa jpa规范 jpa源码
基于springboot最新版本2.1.4.RELEASE,采用jpa为dao层框架,配置redis(redisson)为hibernate的二级缓存。