【问题标题】:Helidon MP ValidationException in injecting MongoDB EntityManager注入 MongoDB EntityManager 中的 Helidon MP ValidationException
【发布时间】:2020-08-08 12:36:59
【问题描述】:

我已经开始学习 Helidon MP 有一段时间了,在教程和我阅读的几乎所有基于这个微服务的源代码中框架,示例写在 H2 数据库上。到目前为止,我找不到任何基于 MongoDB 的示例。我已经知道 eclipselinkMongoDB 开发的 JPA 平台,并尝试了 JPA/NoSQL Examples 中的指南。此外,我实际上可以在一个简单的 Maven 项目中成功运行测试,并且直接使用工厂创建 EntityManager 对象可以正常工作。但是,当我使用 curl 命令访问 http://localhost:8080/person/sahand 时,将其放入 Helidon MP 项目并像说明一样将 CDI 用于 EntityManager 会导致异常。在我放相关代码之前,我刚刚发现当 Helidon 为 NoSQL 数据库访问创建 EntityManager 时,它应该使用 org.eclipse.persistence.eis.EISLogin 对象,而它正在创建 org.eclipse.persistence.sessions.DatabaseLogin 在某些时候导致 ClassCastException 等等上。 这是我得到的例外:

Caused by: Exception [EclipseLink-7108] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.ValidationException
Exception Description: This operation is not supported for non-relational platforms.
        at org.eclipse.persistence.exceptions.ValidationException.notSupportedForDatasource(ValidationException.java:590)
        at org.eclipse.persistence.internal.sessions.AbstractSession.getLogin(AbstractSession.java:2751)
        at io.helidon.integrations.cdi.eclipselink.CDISEPlatform.initializeExternalTransactionController(CDISEPlatform.java:228)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.preConnectDatasource(DatabaseSessionImpl.java:851)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.login(DatabaseSessionImpl.java:823)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:258)
        at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:769)

这是用于数据库访问的资源管理器:

@Path("/person")
@Dependent
public class PersonResourceManager {
    @PersistenceContext
    private EntityManager em;

    @GET
    @Path("/{name}")
    @Produces("text/plain")
    @Transactional
    public String getResponse(@PathParam("name") String name) {
        Query query = em.createQuery("Select p from PERSON p where p.name LIKE '" + name + "'");
        Person person = (Person) query.getResultList().get(0);
        return String.valueOf(person.getAge()) + "\n";
    }
}

这是我试图从已创建的 MongoDB 集合中读取的实体:

@Entity(name = "PERSON")
@NoSql(dataFormat = DataFormatType.MAPPED)
public class Person implements Serializable {
    @Id
    @GeneratedValue
    @Field(name = "_id")
    private String id;

    @Basic
    private String name;

    @Basic
    private int age;

    @Version
    private long version;

    @Deprecated
    protected Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getId() {return id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public int getAge() {return age;}
    public void setAge(int age) {this.age = age;}
}

这些是项目中解析的与数据库相关的maven依赖:

<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>javax.transaction-api</artifactId>
    <version>1.2</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.resource</groupId>
    <artifactId>connector-api</artifactId>
    <version>1.5</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-eclipselink</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-jpa</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-jta-weld</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.helidon.integrations.cdi</groupId>
    <artifactId>helidon-integrations-cdi-datasource-hikaricp</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>jakarta.persistence</groupId>
    <artifactId>jakarta.persistence-api</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>3.12.6</version>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.7.7</version>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.nosql</artifactId>
    <version>2.7.7</version>
</dependency>

persistence.xml 文件中的单位定义:

    <persistence-unit name="mongodb" transaction-type="RESOURCE_LOCAL">
        <class>sahand.example.helidon.Person</class>
        <properties>
            <property name="eclipselink.target-database" value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/>
            <property name="eclipselink.nosql.connection-spec" value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/>
            <property name="eclipselink.nosql.property.mongo.port" value="27017"/>
            <property name="eclipselink.nosql.property.mongo.host" value="localhost"/>
            <property name="eclipselink.nosql.property.mongo.db" value="jpa-nosql-demo"/>
            <property name="eclipselink.logging.level" value="FINEST"/>
        </properties>
    </persistence-unit>

最后,我猜想application.yaml 的一部分是正确的。但是,我很确定在阅读此配置之前会发生异常。

javax:
  sql:
    DataSource:
      person:
        dataSourceClassName: othatrg.eclipse.persistence.nosql.adapters.mongo.MongoPlatform
        dataSource:
          url: mongodb://localhost:27017
          user: sample_user
          password: "samplePass"

如果有人能帮我解决这个问题,我将不胜感激。虽然可以通过工厂创建每个 EntityManager 对象,但我觉得这个解决方案很混乱。要么我使用了错误的依赖关系,要么是我不知道的其他东西。 This 也是我对 Helidon 和 JPA 遵循的指令。

【问题讨论】:

  • 你的问题为什么要问两次?
  • 网络问题导致首次上传失败(虽然没有)
  • 看起来您已将持久性单元设置为资源本地,但堆栈跟踪显示您以某种方式指定使用 ExternalTransactionController,这意味着 JTA - 您引用的 Helidon 文档都显示了 JTA 持久性单元它控制数据源和事务。您将不得不看看他们的数据源如何适合 mongoDB,或者使用完全资源的本地持久性单元(您可以在其中创建 EntityManager 实例,完全自己进行事务分界)
  • 非常感谢您的帮助。我已将 persistence.xml 文件中的事务类型设置为 JTA(如 Helidon 教程所述)。这会导致我从 eclipselink JPA/NoSQL 指令获得的测试失败,但这没关系,因为如果主要问题得到解决,它就可以修复。尽管进行了修改,但问题仍然存在。我假设 java 代码中的事务配置和注释是正确的。问题可能来自依赖关系吗?您可以从链接下载我的完整 pom.xml 文件。
  • 您可能遇到了 Helidon 错误。在 Eclipselink 中引发异常的代码在这里:github.com/eclipse-ee4j/eclipselink/blob/… 初步猜测:看起来 Helidon 正在调用 getLogin() 而不是 getDataSourceLogin()。我会做更多的研究并更新这个问题。

标签: mongodb maven eclipselink helidon


【解决方案1】:

这是一个bug in Helidon,因为 Helidon 中的 JPA 子系统调用的是关系数据库特定的方法 Session#getLogin(),而不是更明显的通用方法 Session#getDatasourceLogin()

fix 应该在 Helidon 2.0.2 中可用。虽然不能保证能解决这个问题,但 Helidon 还是这样做是正确的。

【讨论】:

  • 非常感谢您的帮助。知道 2.0.2 版的发布日期吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 2021-03-15
  • 1970-01-01
  • 2011-05-07
  • 1970-01-01
相关资源
最近更新 更多