【从零开始学习SpirngBoot—常见异常汇总】
在使用JPA的时候,如果对bean的生命周期不了解的话,难免会碰到一些问题,比如:InvalidDataAccessApiUsageException:Removing a detached instance 。
那么这一小节说说实体Bean的生命周期。
1、实体Bean生命周期的4种状态
实体分为被容器管理和不被容器管理两种。可以通过实体管理器的的两个方法进行检测:
contains()用来检查实体是否被管理。
clear()分离实体。
实际上,实体共有4种状态。
new—新实体(新生态):实体由应用产生和实体管理器没有任何联系,也没有唯一的标识符。
managed—持久化实体(或者托管实体)(持久态):新实体和实体管理器产生关联(通过persist()、merge()等方法),在实体管理器中存在和被管理,标志是在实体管理器中有一个唯一的标志。
detached—分离的实体(游离态):实体有唯一的标识,但它的标识不被实体管理器管理。
removed—删除的实体(删除状态):实体被remove()方法删除,对应的记录将会在当前事务提交的时候从数据库中删除。
下面根据调用的方法说说各种状态的转换:
2、状态转换
(1).persist(T entity)
调用persist,新实体状态(new)转化为持久化状态(managed),如果实体已经被持久化,则调用persist方法不会发生任何事情,如果对于一个删除状态的调用persist方法,则删除状态的实体又转变为持久化状态,如果对于一个游离状态(detached)的实体执行persist操作,则抛出IllegalArgumentException异常。
(2).remove(T entity)
通过调用remove方法删除一个持久化的实体,如果实体声明为级联删除,则相关联的实体也被删除。
在一个新实体状态(new)的实体上调用remove操作,将被忽略。(这个是不会抛出任何异常信息的,还有就是这里一定要区分是新生态(new)还是游离态(detached) )。
在游离态的实体上调用remove操作,将抛出IllegalArgumentException异常。
在删除态的实体上调用remove操作,将被忽略。
(3).merge(T entity)
将游离态的实体持久化到数据库中,并转换为持久化状态。
如果A是一个游离态的实体,该方法会将A的修改提交到数据库中,并产生一个managd态的实例A2。
如果A是一个new态的实体,该方法会根据A产生一个managed态的实例A2。
如果是A是一个managed态的实体,它的状态不会改变,但是系统仍然会在数据库中执行update操作。
如果A是remove态的实体,该方法会抛出IllegalArgumentException异常。
(3). 实例理解状态
如果只看理论理解的话,我觉得还是有点不深刻,看看代码:
DemoInfo demoInfo = new DemoInfo();
demoInfo.setName("demoInfo");
以上的这个代码的实体对象状态是 新生态(new)。
如果你修改为如下代码就可不一样了:
DemoInfo demoInfo = new DemoInfo();
demoInfo.setId(1);
demoInfo.setName("demoInfo");
以上代码实体对象状态是 游离态(detached)
在看如下代码:
public void testSave(){
DemoInfo demoInfo = new DemoInfo();
demoInfo.setName("demoInfo");
demoInfoDao.save(demoInfo);
System.out.println(demoInfo);
}
具体的 demoInfoDao.save(demoInfo)代码:
@Transactional
public void save(Object entity){
entityManager.persist(entity);
}
我们分析这个demoInfo的一个状态情况,首先从testSave开始之后new了一个对象出来,然后设置了一些基本信息,在 demoInfoDao.save(demoInfo)之前这个时候,demoInfo处于新生态(new),然后进入到了具体的save(Objectentity)方法,在
entityManager.persist(entity)这个方法之前,demoInfo仍然是处于新生态(new),当执行entityManager.persist(entity)这个方法之后,demoInfo此时demoInfo就处于持久状态(managed),然后save方法执行完毕,返回到testSave()方法继续往下执行,此时的demoInfo就是游离状态(detached)了,此时的游离对象在执行remove方法是抛出异常的 InvalidDataAccessApiUsageException:Removing adetached instance com.kfit.demo.bean.DemoInfo。