Ktor中JPA连接MongoDB报错:找不到Mdb的EntityManager持久化提供者
我在Ktor应用里搭建同时访问MySQL和MongoDB的JPA环境,MySQL部分正常,但MongoDB连接失败,报错jakarta.persistence.PersistenceException: No Persistence provider for EntityManager named Mdb,系统检测不到MongoDB的持久化提供者。相关文件如下:
persistence.xml文件(路径:/Kotlin/JPA/src/main/resources/META-INF/persistence.xml)
<?xml version="1.0" encoding="UTF-8"?> <!-- <persistence version="3.0" xmlns="https://jakarta.ee/xml/ns/persistence">--> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="pu"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>com.example.data.Student</class> <properties> <property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/> <property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/Students"/> <property name="jakarta.persistence.jdbc.user" value="root"/> <property name="jakarta.persistence.jdbc.password" value="mynewpassword"/> </properties> </persistence-unit> <persistence-unit name="Mdb" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider> <class>com.example.data.Student</class> <properties> <property name="hibernate.ogm.datastore.provider" value="mongodb"/> <property name="hibernate.ogm.datastore.host" value="localhost:27017"/> <property name="hibernate.ogm.datastore.database" value="databasename"/> <property name="hibernate.ogm.datastore.create_database" value="true"/> </properties> </persistence-unit> </persistence>
Routing.kt文件(路径:plugins目录下)
fun Application.configureRouting() { install(ContentNegotiation) { json() } routing { get("/") { call.respondText("Hello World!") } get("/jpa") { val a = Student(3, "George", "Python") val emf: EntityManagerFactory = Persistence.createEntityManagerFactory("Mdb") val em: EntityManager = emf.createEntityManager() em.transaction.begin() em.persist(a) em.transaction.commit() println(a) call.respond(HttpStatusCode.OK, "Working") } } }
实体类Student.kt
package com.example.data import jakarta.persistence.Entity import jakarta.persistence.Id @Entity class Student( @Id val id: Int, val name: String, val tech: String )
build.gradle.kts文件
val ktor_version: String by project val kotlin_version: String by project val logback_version: String by project dependencies { implementation("io.ktor:ktor-server-core-jvm:$ktor_version") implementation("io.ktor:ktor-server-locations-jvm:$ktor_version") implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktor_version") implementation("io.ktor:ktor-serialization-jackson-jvm:$ktor_version") implementation("io.ktor:ktor-serialization-gson-jvm:$ktor_version") implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version") implementation("io.ktor:ktor-server-netty-jvm:$ktor_version") implementation("ch.qos.logback:logback-classic:$logback_version") testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") implementation("org.jetbrains.kotlin:kotlin-maven-plugin:1.2.30") implementation("org.jetbrains.kotlin:kotlin-maven-noarg:1.2.30") implementation("org.hibernate:hibernate-core:6.1.0.Final") implementation("org.jetbrains.exposed:exposed-dao:0.38.2") implementation("org.jetbrains.exposed:exposed-jdbc:0.38.2") implementation("org.ktorm:ktorm-core:3.5.0") implementation("mysql:mysql-connector-java:8.0.29") implementation("org.mongodb:mongo-java-driver:3.12.11") implementation ("org.hibernate.ogm:hibernate-ogm-mongodb:5.4.1.Final") implementation("jakarta.transaction:jakarta.transaction-api:2.0.1") // implementation("javax.transaction:jta:1.1") // implementation("org.hibernate:hibernate-entitymanager:6.0.0.Alpha7") }
错误日志
2022-07-22 18:29:58.431 [eventLoopGroupProxy-4-1] TRACE o.h.j.b.i.PersistenceXmlParser - Persistence unit name from persistence.xml : Mdb 2022-07-22 18:29:58.431 [eventLoopGroupProxy-4-1] DEBUG o.h.jpa.HibernatePersistenceProvider - Located and parsed 2 persistence units; checking each 2022-07-22 18:29:58.431 [eventLoopGroupProxy-4-1] DEBUG o.h.jpa.HibernatePersistenceProvider - Checking persistence-unit [name=pu, explicit-provider=org.hibernate.jpa.HibernatePersistenceProvider] against incoming persistence unit name [Mdb] 2022-07-22 18:29:58.431 [eventLoopGroupProxy-4-1] DEBUG o.h.jpa.HibernatePersistenceProvider - Excluding from consideration due to name mis-match 2022-07-22 18:29:58.431 [eventLoopGroupProxy-4-1] DEBUG o.h.jpa.HibernatePersistenceProvider - Checking persistence-unit [name=Mdb, explicit-provider=org.hibernate.ogm.jpa.HibernateOgmPersistence] against incoming persistence unit name [Mdb] 2022-07-22 18:29:58.432 [eventLoopGroupProxy-4-1] DEBUG o.h.jpa.boot.spi.ProviderChecker - Persistence-unit [Mdb] requested PersistenceProvider [org.hibernate.ogm.jpa.HibernateOgmPersistence] 2022-07-22 18:29:58.432 [eventLoopGroupProxy-4-1] TRACE o.h.jpa.boot.spi.ProviderChecker - Checking requested PersistenceProvider name [org.hibernate.ogm.jpa.HibernateOgmPersistence] against Hibernate provider names 2022-07-22 18:29:58.432 [eventLoopGroupProxy-4-1] DEBUG o.h.jpa.HibernatePersistenceProvider - Excluding from consideration due to provider mis-match 2022-07-22 18:29:58.433 [eventLoopGroupProxy-4-1] DEBUG o.h.jpa.HibernatePersistenceProvider - Found no matching persistence units 2022-07-22 18:29:58.434 [eventLoopGroupProxy-4-1] TRACE o.h.jpa.HibernatePersistenceProvider - Could not obtain matching EntityManagerFactoryBuilder, returning null 2022-07-22 18:29:58.550 [eventLoopGroupProxy-4-1] ERROR ktor.application - Unhandled: GET - /jpa jakarta.persistence.PersistenceException: No Persistence provider for EntityManager named Mdb
问题分析与解决方案
核心问题
依赖版本严重不兼容
Hibernate Core 6.1.0.Final是Jakarta EE 9+版本,而Hibernate OGM MongoDB 5.4.1.Final仅兼容Hibernate Core 5.x(Java EE 8及以下),版本跨度导致OGM的持久化提供者无法被Hibernate Core 6.x识别加载。命名空间与API前缀冲突
persistence.xml使用了旧的Java EE命名空间,但依赖中混合了Jakarta EE的事务API,导致配置解析时出现不匹配,同时Hibernate 5.x需要使用javax.persistence前缀而非jakarta.persistence。实体类重复配置风险
同一个Student实体同时注册到两个不同类型的持久化单元(关系型+文档型),会引发实体映射逻辑冲突,后续可能出现更多未知问题。
修正步骤
1. 统一依赖版本,移除冲突依赖
修改build.gradle.kts,使用与Hibernate OGM 5.4.x兼容的Hibernate Core 5.x版本,同时调整Mongo驱动和事务API:
val ktor_version: String by project val kotlin_version: String by project val logback_version: String by project dependencies { implementation("io.ktor:ktor-server-core-jvm:$ktor_version") implementation("io.ktor:ktor-server-locations-jvm:$ktor_version") implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktor_version") implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version") implementation("io.ktor:ktor-server-netty-jvm:$ktor_version") implementation("ch.qos.logback:logback-classic:$logback_version") testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") // 移除无用的Maven插件依赖 implementation("org.jetbrains.kotlin:kotlin-maven-noarg:1.2.30") // 使用与OGM兼容的Hibernate版本 implementation("org.hibernate:hibernate-core:5.6.14.Final") implementation("org.hibernate:hibernate-entitymanager:5.6.14.Final") implementation("org.jetbrains.exposed:exposed-dao:0.38.2") implementation("org.jetbrains.exposed:exposed-jdbc:0.38.2") implementation("org.ktorm:ktorm-core:3.5.0") implementation("mysql:mysql-connector-java:8.0.29") // 替换为OGM兼容的Mongo同步驱动 implementation("org.mongodb:mongodb-driver-sync:4.6.1") implementation("org.hibernate.ogm:hibernate-ogm-mongodb:5.4.1.Final") // 使用Java EE的JTA API,适配Hibernate 5.x implementation("javax.transaction:jta:1.1") // 移除Jakarta版本API,避免冲突 // implementation("jakarta.transaction:jakarta.transaction-api:2.0.1") }
2. 修正persistence.xml配置
更新命名空间为JPA 2.1,统一使用javax.persistence前缀,并为MongoDB单独指定实体类:
<?xml version="1.0" encoding="UTF-8"?> <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-unit name="pu" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>com.example.data.Student</class> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/Students"/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="mynewpassword"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> <persistence-unit name="Mdb" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider> <class>com.example.data.MongoStudent</class> <properties> <property name="hibernate.ogm.datastore.provider" value="mongodb"/> <property name="hibernate.ogm.datastore.host" value="localhost:27017"/> <property name="hibernate.ogm.datastore.database" value="databasename"/> <property name="hibernate.ogm.datastore.create_database" value="true"/> </properties> </persistence-unit> </persistence>
3. 创建MongoDB专属实体类
避免实体类跨数据源冲突,创建MongoStudent类,使用javax.persistence注解:
package com.example.data import javax.persistence.Entity import javax.persistence.Id @Entity class MongoStudent( @Id val id: Int, val name: String, val tech: String )
4. 更新路由中的实体引用
修改Routing.kt,使用新创建的MongoStudent实体:
fun Application.configureRouting() { install(ContentNegotiation) { json() } routing { get("/") { call.respondText("Hello World!") } get("/jpa") { val a = MongoStudent(3, "George", "Python") val emf: EntityManagerFactory = Persistence.createEntityManagerFactory("Mdb") val em: EntityManager = emf.createEntityManager() em.transaction.begin() em.persist(a) em.transaction.commit() println(a) call.respond(HttpStatusCode.OK, "Working") } } }
内容的提问来源于stack exchange,提问作者Anandakrishnan

