使用Hibernate OGM和云MongoDB Atlas M0(免费层)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Hibernate OGM和云MongoDB Atlas M0(免费层)相关的知识,希望对你有一定的参考价值。

我正在尝试将MongoDB Atlas M0(免费套餐)用于我的JAVA EE应用程序,现在我正在使用:

  • 本地MongoDB数据库(v4.0.4)
  • Hibernate Core“hibernate-core 5.3.6.Final”
  • Hibernate GMO“hibernate-ogm-mongodb 5.3.1.Final”
  • Java应用程序服务器WildFly 15.0.0.Final。

使用本地数据库,一对MongoDB和Hibernate OGM就像魅力一样,但当我尝试将Hibernate与Mongo Atlas连接到免费层以测试云数据库时,我无法建立有效的连接,因为mongodb驱动程序会抛出异常com.mongodb.MongoSocketReadException:过早地到达流的末尾

我将提供两个版本的persistence.xml,第一个是使用localhost工作正常,第二个是我用来连接到云的版本。

工作localhost版本:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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_2.xsd"
             version="2.2">

    <!--   @@@   MongoDB   HIBERNATE   OGM   PERSISTENCE   UNIT   @@@   -->
    <persistence-unit name="PersistenceUnitNoSQL" transaction-type="JTA">

        <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>

        <class>org.companyname.model.UserEntity</class>
        <class>org.companyname.model.ItemEntity</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>

不工作的地图集云版:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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_2.xsd"
             version="2.2">

    <!--   @@@   MongoDB   HIBERNATE   OGM   PERSISTENCE   UNIT   @@@   -->
    <persistence-unit name="PersistenceUnitNoSQL" transaction-type="JTA">

        <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>

        <class>org.companyname.model.UserEntity</class>
        <class>org.companyname.model.ItemEntity</class>

        <properties>

            <property name="hibernate.ogm.datastore.provider" value="mongodb"/>
            <property name="hibernate.ogm.datastore.host" value="cluster0-clustername-shard-00-00-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-01-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017"/>

            <property name="hibernate.ogm.datastore.database" value="databasename"/>
            <property name="hibernate.ogm.datastore.create_database" value="true"/>

        <property name="hibernate.ogm.datastore.username" value="atlas-user-name"/>
        <property name="hibernate.ogm.datastore.password" value="atlas-user-password"/>
        <property name="hibernate.ogm.mongodb.authentication_mechanism" value="SCRAM_SHA_1"/>

        </properties>

    </persistence-unit>

</persistence>

像主机一样,我使用来自Atlas帐户帮助窗口的“标准连接字符串”的副本集URI,因为“短SRV连接字符串”Hibernate抛出org.hibernate.service.spi.ServiceException:OGM000072:无法配置数据存储提供程序,所以我认为还没有这种连接的支持。

因此,使用此最后一个persistence.xml配置,我遇到以下错误:

20:02:01,094 INFO  [org.mongodb.driver.cluster] (ServerService Thread Pool -- 78) Cluster description not yet available. Waiting for 30000 ms before timing out
20:02:01,175 INFO  [org.mongodb.driver.cluster] (cluster-ClusterId{value='5c5497a97aea6111622c7540', description='null'}-cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017)
Exception in monitor thread while connecting to server cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017: com.mongodb.MongoSocketReadException: Prematurely reached end of stream
    at com.mongodb.internal.connection.SocketStream.read(SocketStream.java:112)
    at com.mongodb.internal.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.java:570)
    at com.mongodb.internal.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.java:441)
    at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:295)
    at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:255)
    at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:83)
    at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:33)
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:106)
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:63)
    at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:127)
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:117)
    at java.lang.Thread.run(Thread.java:748)

Hibernate尝试连接到每个分片(00-00,00-01,00-02),但是所有抛出此异常。

我试图解决这个问题:

  • 使用mongo-java-driver版本3.9.1代替内置的Hibernate 3.6.3,但两个驱动程序都使用相同的问题
  • 我的IP已添加(我的应用程序从我的笔记本电脑部署)到我的atlas帐户IP白名单
  • 我可以很好地连接Mongo Shell和MongoDB Compass的集群
  • 我对“hibernate.ogm.mongodb.authentication_mechanism”有疑问,但“SCRAM_SHA_1”和“BEST”对我没用
  • 最后我尝试直接从Java连接到集群(没有Hibernate)

MongoClient mongoClient = MongoClients.create("mongodb+srv://atlas-user-name:atlas-user-password@cluster0-clustername-raa4n.mongodb.net/test?retryWrites=true");

要么

MongoClient mongoClient = MongoClients.create("mongodb://atlas-user-name:atlas-user-password@cluster0-clustername-shard-00-00-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-01-raa4n.mongodb.net:27017,cluster0-clustername-shard-00-02-raa4n.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-clustername-shard-0&authSource=admin&retryWrites=true");

两个案例都运行良好,我能够建立连接并使用数据库没有问题。

所以我的问题是为什么Hibernate抛出这种异常?

答案

Hibernate OGM创建客户端的方式可能不正确。

我认为现在更容易检查这个问题的方法是覆盖MongoDBDatastoreProvider并提供一个初始化的MongoClient。

您可以通过扩展MongoDBDatastoreProvider并覆盖createMongoClient方法来完成此操作。就像是:

package org.myprojects;

import org.hibernate.ogm.datastore.mongodb.impl.MongoDBDatastoreProvider;

public class MYCustomMongoDBDatastoreProvider extends MongoDBDatastoreProvider {

    @Override
    protected MongoClient createMongoClient(MongoDBConfiguration config) {    
       return MongoClients.create(...);
    }

}

然后使用属性OgmProperties.DATASTORE_PROVIDER来使用您的数据存储提供程序:

hibernate.ogm.datastore.provider = org.myprojects.MYCustomMongoDBDatastoreProvider

在这个例子中,我在hibernate.properties文件中设置它,但你可以将它设置在对你的项目更有意义的地方。

编辑:有关错误的其他说明。

I think the problems is that we are not using the factory to create the mongo client

编辑2:问题可能是由于缺乏对SSL的支持。 An issue has been created并包含更多信息

以上是关于使用Hibernate OGM和云MongoDB Atlas M0(免费层)的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data MongoDB 和 Hibernate OGM for MongoDB 有啥区别?

Hibernate OGM映射本地查询的@Embeddable对象

Hibernate OGM 映射本机查询的@Embeddable 对象

MongoDB:不支持 PLAIN 方法

当我尝试使用 Hibernate ogm 和 spring boot 时,控制台给出“无法实例化命名策略类”错误

wildfly 10上使用最新的 Hibernate ORM OGM