如何解决java.lang.NoSuchMethodError: EntityManager.createStoredProcedureQuery异常
EntityManager.createStoredProcedureQuery抛出NoSuchMethodError的问题 兄弟,你这个错误我太熟了——本质就是你调用的createStoredProcedureQuery(String)是JPA 2.1才新增的API,但你的运行环境实际用的JPA版本还停留在2.0或者更早,导致JVM找不到这个方法。结合你提到的WebLogic 12.1.2,下面是具体的排查和修复步骤:
1. 先确认WebLogic的JPA 2.1启用配置是否真的生效
WebLogic 12.1.2默认是用JPA 2.0的,要切换到2.1必须手动配置,你可以逐一核对:
检查
weblogic.xml(或EJB模块的weblogic-ejb-jar.xml):
确保你的Web应用的WEB-INF/weblogic.xml里添加了JPA 2.1的配置节点,注意命名空间要正确:<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"> <!-- 其他配置 --> <persistence-configuration> <persistence-unit-defaults> <jpa-version>2.1</jpa-version> </persistence-unit-defaults> </persistence-configuration> </weblogic-web-app>如果是EJB模块,就把这段配置放到
META-INF/weblogic-ejb-jar.xml里。核对
persistence.xml的JPA版本声明:
你的persistence.xml必须明确指定JPA 2.1的版本,不能用旧的2.0 schema:<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1"> <!-- 你的持久化单元配置 --> </persistence>这里的
version="2.1"和对应的schema地址是关键,别写错成2.0的。
2. 排查类加载冲突(最容易踩坑的点)
WebLogic的类加载机制很容易出现jar包冲突,如果你应用里自带了旧版本的JPA相关jar,就会覆盖WebLogic自带的JPA 2.1实现:
- 检查你的
WEB-INF/lib(或EJB模块的lib目录),删掉所有旧的JPA API jar,比如persistence-api-1.0.jar、javax.persistence_2.0.x.jar这类,让WebLogic自带的JPA 2.1 API来主导。 - 如果是Maven项目,把JPA相关依赖的scope设为
provided,因为WebLogic已经提供了这些类:<dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency>
3. 验证WebLogic是否真的加载了JPA 2.1
你可以查看WebLogic的启动日志,搜索JPA Version相关的内容,如果日志里显示的是2.1,说明配置生效了;如果还是2.0,那大概率是前面的配置文件位置不对或者命名空间写错了,得重新核对。
4. 顺带提下存储过程调用的正确姿势(避免后续踩坑)
等你解决了版本问题后,调用这个带5个输入、1个输出参数的存储过程时,要注意参数的注册和赋值:
StoredProcedureQuery spq = em.createStoredProcedureQuery("User_pkg.Store_user_proc"); // 注册输入参数(按顺序,1到5) spq.registerStoredProcedureParameter(1, String.class, ParameterMode.IN); spq.registerStoredProcedureParameter(2, Integer.class, ParameterMode.IN); spq.registerStoredProcedureParameter(3, Date.class, ParameterMode.IN); spq.registerStoredProcedureParameter(4, String.class, ParameterMode.IN); spq.registerStoredProcedureParameter(5, Boolean.class, ParameterMode.IN); // 注册输出参数(第6个) spq.registerStoredProcedureParameter(6, Integer.class, ParameterMode.OUT); // 给输入参数赋值 spq.setParameter(1, "testUser"); spq.setParameter(2, 1001); // ... 剩下3个输入参数按顺序赋值 // 执行存储过程 spq.execute(); // 获取输出参数结果 Integer outputResult = (Integer) spq.getOutputParameterValue(6);
内容的提问来源于stack exchange,提问作者user3820413

