0%

LazyInitializationException

文章字数:564,阅读全文大约需要2分钟

记一次查找问题的过程

  1. 做一个用jpa从数据库中查找数据,修改再保存到数据库的简单功能。

  2. 查找出来后使用BeanUtil将修改的信息放入jpa的对象中,结果报了错误
    Could not copy property 'id' from source to target

  3. 查看BeanUtil的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}

Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}

writeMethod.invoke(target, value);
} catch (Throwable var15) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
}
}

发现在反射调用失败后统一返回这个异常,于是打断点。果然是反射报的异常。

  1. 检查属性是否一一对应,是否有公共的getset,是否有基础类型(有的话传入空会空指针)

  2. 都没发现有问题,于是手动赋值又运行了一遍。

1
a.setId(b.getId());
  1. 期初只是为了测试一下方法是否被私有化,属性名是否一致。结果抛出异常LazyInitializationException

  2. 这才是导致反射出错的原因,异常信息的意思大致是session被关闭。在stackoverflow上找到解决方法:方法上加上@Transactional

  3. 最后成功解决问题,回想了一下。当元素或者元素的lazy属性为true时执行find()得到的只是一个代理对象,只有执行getId()时才会从数据库中取。然后取的时候事务已经关闭了。(可能是因为find操作是在Stream流中进行的,流关闭事务也关闭了)加上@Transactional注解可以使代码块事务统一。