【从零开始学习SpirngBoot—常见异常汇总】

       在使用JPA的时候,如果对bean的生命周期不了解的话,难免会碰到一些问题,比如:InvalidDataAccessApiUsageException:Removing a detached instance 。

       那么这一小节说说实体Bean的生命周期。

1、实体Bean生命周期的4种状态

实体分为被容器管理和不被容器管理两种。可以通过实体管理器的的两个方法进行检测:
   contains()用来检查实体是否被管理。
   clear()分离实体。

 JPA实体Bean的生命周期_JPA

实际上,实体共有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。