OpenJPA FailedObject: * [org.apache.openjpa.util.IntId] [java.lang.String] 错误

Exception in thread "main" <openjpa-2.4.2-r422266:1777108 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: null FailedObject: 351 [org.apache.openjpa.util.IntId] [java.lang.String]

今天在学习 OpenJPA 时,在 @OneToMany 中指定 fetch 属性为 FetchType.EAGER,实现一对多关系中的多的这方数据及时加载,不进行延迟加载(OpenJPA 默认开启延迟加载)。

但是,在运行实例时,输出如下错误日志信息:

2391  demo1  INFO   [main] openjpa.Enhance - Creating subclass and redefining methods for "[class com.huangx.openjpa.lazy.demo1.Teacher, class com.huangx.openjpa.lazy.demo1.Student]". This means that your application will be less efficient than it would if you ran the OpenJPA enhancer.
3328  demo1  TRACE  [main] openjpa.jdbc.SQL - <t 1729779847, conn 1431467659> executing prepstmnt 142247393 SELECT t0.name, t1.TEACHER_ID, t2.id, t2.name, t2.salary, t2.sex FROM Teacher t0 LEFT OUTER JOIN Teacher_Student t1 ON t0.id = t1.TEACHER_ID LEFT OUTER JOIN Student t2 ON t1.STUDENTLIST_ID = t2.id WHERE t0.id = ? ORDER BY t1.TEACHER_ID ASC [params=?]
3344  demo1  TRACE  [main] openjpa.jdbc.SQL - <t 1729779847, conn 1431467659> [16 ms] spent
Exception in thread "main" <openjpa-2.4.2-r422266:1777108 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: null
FailedObject: 351 [org.apache.openjpa.util.IntId] [java.lang.String]
    at org.apache.openjpa.kernel.BrokerImpl.find(BrokerImpl.java:1029)
    at org.apache.openjpa.kernel.BrokerImpl.find(BrokerImpl.java:923)
    at org.apache.openjpa.kernel.DelegatingBroker.find(DelegatingBroker.java:230)
    at org.apache.openjpa.persistence.EntityManagerImpl.find(EntityManagerImpl.java:488)
    at com.huangx.openjpa.lazy.demo1.Demo.main(Demo.java:18)
Caused by: java.lang.NullPointerException
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.setInverseRelation(JDBCStoreManager.java:452)
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.initializeState(JDBCStoreManager.java:412)
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.initialize(JDBCStoreManager.java:305)
    at org.apache.openjpa.kernel.DelegatingStoreManager.initialize(DelegatingStoreManager.java:112)
    at org.apache.openjpa.kernel.ROPStoreManager.initialize(ROPStoreManager.java:57)
    at org.apache.openjpa.kernel.BrokerImpl.initialize(BrokerImpl.java:1048)
    at org.apache.openjpa.kernel.BrokerImpl.find(BrokerImpl.java:1006)
    ... 4 more

实例代码

(1)Student.java 代码

@Data
@Entity
@Table
public class Student {
    @Id
    @GeneratedValue
    private int id;

    @Column
    private String name;

    @Column
    private String sex;

    @Column
    private float salary;
}

(2)Teacher.java 代码

@Data
@Entity
@Table
public class Teacher {
    @Id
    @GeneratedValue
    private int id;

    @Column
    private String name;

    // FetchType.EAGER 表示立即加载 Student 数据
    @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Student> studentList;
}

(3)客户端代码

EntityManagerFactory emf = Persistence.createEntityManagerFactory(NAME);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

// 初始化数据
Teacher teacher = em.find(Teacher.class, 351);
System.out.println("id = " + teacher.getId());
System.out.println("name = " + teacher.getName());
List<Student> studentList = teacher.getStudentList();
for(Student student : studentList) {
    System.out.println(student);
}

em.getTransaction().commit();
em.close();
emf.close();
System.out.println("finished.");

运行上面客户端代码,将执行如下 SQL 语句:

SELECT t0.name, t1.TEACHER_ID, t2.id, t2.name, t2.salary, t2.sex 
FROM Teacher t0 
LEFT OUTER JOIN Teacher_Student t1 ON t0.id = t1.TEACHER_ID 
LEFT OUTER JOIN Student t2 ON t1.STUDENTLIST_ID = t2.id 
WHERE t0.id = 351 ORDER BY t1.TEACHER_ID ASC;

上面 SQL 语句中没有匹配 Teacher 实体的 id 字段,并且通过打断点分析源码。如下图:

OpenJPA FailedObject: * [org.apache.openjpa.util.IntId] [java.lang.String] 错误

上图中,红框中的语句抛出了 NullPointerException 异常。这是因为没有获取到 ClassMapping(即 cm),为什么 cm 变量为空呢?接下来看下图:

OpenJPA FailedObject: * [org.apache.openjpa.util.IntId] [java.lang.String] 错误

上图中,_conf.getMetaDataRepositoryInstance() 方法返回了 MetaDataRepository 对象,该对象中的 _metas 属性中存放了实体信息。继续看下图:

OpenJPA FailedObject: * [org.apache.openjpa.util.IntId] [java.lang.String] 错误

上图中,pc.getClass() 返回目标实体的 Class 属性,然后使用 _conf.getMetaDataRepositoryInstance().getCachedMetaData() 方法获取对应的 ClassMapping。然而,上面两张图片的实体类型并不一致,其中:

  • _conf.getMetaDataRepositoryInstance() 的 _metas 类型为 com.huangx.openjpa.lazy.demo1.Student

  • pc.getClass() 类型为 org.apache.openjpa.enhance.com$huangx$openjpa$lazy$demo1$Student$pcsubclass

看书和学习是思想的经常营养,是思想的无穷发展。 —— 冈察洛夫
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号