Helidon MP 2.5中Hibernate createQuery()报ORA-00933错误求助
问题
在Helidon MP 2.5环境中连接Oracle数据库,使用Hibernate作为JPA提供者,通过通用抽象CRUD仓库的findAll()方法实现实体分页查询时,抛出ORA-00933错误。
仓库代码
public abstract class CrudRepository<T, ID> implements CrudInterface<T, ID> { protected final Class<T> persistentClass; private final SessionFactory sessionFactory; private static final Logger log = Logger.getLogger(CrudRepository.class.getName()); protected CrudRepository(Class<T> persistenceClass, HelidonPersistenceUnitInfo hpuInfo) { this.persistentClass = persistenceClass; this.sessionFactory = new org.hibernate.cfg.Configuration() .addProperties(hpuInfo.getProperties()) .addAnnotatedClass(persistenceClass) .buildSessionFactory(); } public Page<T> findAll(Pageable pageableObj) { List<T> list; int page = pageableObj.getPageNum(); int size = pageableObj.getMaxRows(); if(page < 0 || size < 0) { throw new IllegalArgumentException("Invalid values for page and size"); } StringBuilder queryStr = new StringBuilder("SELECT e FROM " + persistentClass.getSimpleName() + " e"); log.info("SQL QUERY IS: " + queryStr.toString()); try (Session session = sessionFactory.openSession()) { Query<T> query = session.createQuery(queryStr.toString(), persistentClass); query.setFirstResult(page * size); query.setMaxResults(size); list = query.getResultList(); return new Page<T>(list, pageableObj); } catch (Exception e) { throw new RuntimeException("Failed to find entities", e); } } }
测试用例
@Test void getEmployees() throws Exception { EmployeeRepository empRepo = new EmployeeRepository(); Page<Employee> p = empRepo.findAll(new Pageable(0, 20)); assertEquals(p.getEntities().size(), 20); }
错误关键信息
Caused by: Error : 933, Position : 22, Sql = SELECT e FROM EMPLOYEE e limit :1 , OriginalSql = SELECT e FROM EMPLOYEE e limit ?, Error Msg = ORA-00933: SQL命令未正确结束
已尝试在查询语句后加分号、改用createSQLQuery()替代createQuery(),问题仍未解决。
原因及解决方案
核心原因
Hibernate生成了MySQL风格的limit分页语法,但Oracle数据库不支持limit关键字(Oracle 12c前用ROWNUM,12c及以后用OFFSET ... FETCH NEXT ... ROWS ONLY)。问题根源是未正确配置Hibernate的Oracle方言,导致Hibernate无法生成适配Oracle的分页SQL。
解决方案
配置Oracle方言
在Helidon配置文件(如persistence.xml或application.properties)中添加Hibernate方言配置:- Oracle 12c及以上版本:
hibernate.dialect=org.hibernate.dialect.Oracle12cDialect - Oracle 11g及以下版本:
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
确保该配置被正确加载到
hpuInfo.getProperties()中,Hibernate会根据方言自动生成正确的分页SQL。- Oracle 12c及以上版本:
手动指定方言(若配置未生效)
如果Helidon的PersistenceUnitInfo未加载到方言配置,可在SessionFactory创建时手动添加:this.sessionFactory = new org.hibernate.cfg.Configuration() .addProperties(hpuInfo.getProperties()) .setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect") .addAnnotatedClass(persistenceClass) .buildSessionFactory();依赖JPA标准分页API
无需手动在JPQL中添加分页关键字,setFirstResult()和setMaxResults()是JPA标准分页方法,只要方言配置正确,Hibernate会自动转换为Oracle支持的分页语法。
内容的提问来源于stack exchange,提问作者swing1234

