Статьи

Как подключиться к MongoDB из приложения без сохранения состояния Java EE

В этой статье я расскажу, как подключиться к MongoDB из приложения Java EE без сохранения состояния, чтобы воспользоваться встроенным пулом подключений к базе данных, предлагаемым драйвером MongoDB Java Driver. Это может иметь место при разработке REST API, который выполняет операции с MongoDB.

Получите драйвер Java MongoDb

Для подключения из Java к MongoDB вы можете использовать драйвер Java MongoDB . Если вы создаете свое приложение с помощью Maven, вы можете добавить зависимость в файл pom.xml:

Зависимость Java-драйвера MongoDB

1
2
3
4
5
<dependency>
    <groupid>org.mongodb</groupid>
    <artifactid>mongo-java-driver</artifactid>
    <version>2.12.3</version>
</dependency>

Драйвер предоставляет клиенту MongoDB (com.mongodb.MongoClient) внутренний пул. Класс MongoClient разработан для обеспечения многопоточности и совместного использования между потоками. Для большинства приложений у вас должно быть одно хранилище MongoClient для всей JVM. По этой причине вам не нужно создавать новое хранилище MongoClient с каждым запросом в приложении Java EE без сохранения состояния.

Реализация @Singleton EJB

Простое решение — использовать @Singleton EJB для хранения MongoClient:

Синглтон будет держать MongoClient

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package org.codingpedia.demo.mongoconnection;
 
import java.net.UnknownHostException;
 
import javax.annotation.PostConstruct;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
 
import com.mongodb.MongoClient;
 
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class MongoClientProvider {
         
    private MongoClient mongoClient = null;
         
    @Lock(LockType.READ)
    public MongoClient getMongoClient(){   
        return mongoClient;
    }
     
    @PostConstruct
    public void init() {
        String mongoIpAddress = "x.x.x.x";
        Integer mongoPort = 11000;
        try {
            mongoClient = new MongoClient(mongoIpAddress, mongoPort);
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }      
    }
         
}

Замечания:

  • @Singleton — наверное, самая важная строка кода в этом классе. Эта аннотация указывает, что в приложении будет ровно один синглтон этого типа компонента. Этот бин может быть вызван одновременно несколькими потоками. Он также поставляется с аннотацией @PostConstruct . Эта аннотация используется для метода, который необходимо выполнить после внедрения зависимости для выполнения любой инициализации — в нашем случае это инициализация MongoClient
  • @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) объявляет тип управления параллелизмом одноэлементного сессионного компонента. По умолчанию он имеет значение « Container, я использую его здесь только для выделения его существования. Другой параметр ConcurrencyManagementType.BEAN указывает, что разработчик компонента отвечает за управление одновременным доступом к экземпляру компонента.
  • @Lock(LockType.READ) указывает тип блокировки параллелизма для одноэлементных компонентов с параллелизмом, управляемым контейнером. Когда установлено значение LockType.READ , он применяет метод для разрешения полного одновременного доступа к нему (при условии, что блокировки записи не удерживаются). Это позволяет нескольким потокам обращаться к одному экземпляру MongoClient и использовать преимущества внутреннего пула соединений с базой данных. Это ОЧЕНЬ ВАЖНО, потому что другой более консервативный параметр @Lock(LockType.WRITE) является DEFAULT и обеспечивает эксклюзивный доступ к экземпляру компонента. Это должно замедлить метод в среде с высокой степенью параллелизма …

Используйте @Singleton EJB

Теперь, когда у вас есть MongoClient, «сохраненный» в приложении, вы можете внедрить MongoClientProvider для доступа к MongoDB (например, для получения имен коллекции):

Доступ к MongoClient из других бинов

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package org.codingpedia.demo.mongoconnection;
 
import java.util.Set;
 
import javax.ejb.EJB;
import javax.ejb.Stateless;
 
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.util.JSON;
 
@Stateless
public class TestMongoClientProvider {
     
    @EJB
    MongoClientProvider mongoClientProvider;
     
    public Set<String> getCollectionNames(){
         
        MongoClient mongoClient = mongoClientProvider.getMongoClient();
         
        DB db = mongoClient.getDB("myMongoDB");    
        Set<String> colls = db.getCollectionNames();
         
        for (String s : colls) {
            System.out.println(s);
        }      
         
        return colls;
    }
     
}

Примечание. Объект db будет подключаться к серверу MongoDB для указанной базы данных. С его помощью вы можете выполнять дальнейшие операции. Я рекомендую вам прочитать « Начало работы с драйвером Java», чтобы узнать больше об этом…

Знать

Один аспект, на который нужно обратить внимание:

«Для каждого запроса к БД (поиск, вставка и т. Д.) Поток Java получит соединение из пула, выполнит операцию и освободит соединение. Это означает, что используемое соединение (розетка) может каждый раз отличаться.

Кроме того, в случае набора реплик с включенной опцией slaveOk операции чтения будут равномерно распределены по всем ведомым. Это означает, что в одном и том же потоке запись, за которой следует чтение, может быть отправлена ​​на разные серверы (главный, а затем подчиненный). В свою очередь, операция чтения может не видеть только что записанные данные, поскольку репликация является асинхронной. Если вы хотите обеспечить полную согласованность в «сеансе» (может быть, запрос http), вы бы хотели, чтобы драйвер использовал тот же сокет, чего вы можете добиться, используя «согласованный запрос». Вызовите requestStart () перед вашими операциями и requestDone (), чтобы освободить соединение обратно в пул:

Обеспечение полной согласованности в

1
2
3
4
5
6
7
8
9
<em>DB db...;
db.requestStart();
try {
   db.requestEnsureConnection();
 
   code....
} finally {
   db.requestDone();
}</em>

DB и DBCollection полностью DBCollection . На самом деле они кэшируются, поэтому вы получаете один и тот же экземпляр, несмотря ни на что ». [3]

Ресурсы

  1. Java MongoDB Драйвер
  2. Начало работы с драйвером Java
  3. Параллелизм драйвера Java
  4. GitHub — примеры mongodb / mongo-java-driver