Enterprise Java

How to connect to MongoDB from a Java EE stateless application

In this post I will present how to connect to MongoDB from a stateless Java EE application, to take advantage of the built-in pool of connections to the database offered by the MongoDB Java Driver. This might be the case if you develop a REST API, that executes operations against a MongoDB.

Get the Java MongoDb Driver

To connect from Java to MongoDB, you can use the Java MongoDB Driver.  If you are building your application with Maven, you can add the dependency to the pom.xml file:

MongoDB java driver dependency

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

The driver provides a MongoDB client (com.mongodb.MongoClient) with internal pooling. The MongoClient class is designed to be thread safe and shared among threads. For most applications, you should have one MongoClient instace for the entire JVM. Because of that you wouldn’t want create a new MongoClient instace with each request in your Java EE stateless application.

Implement a @Singleton EJB

A simple solution is to use a @Singleton EJB to hold the MongoClient:

Singleton to hold the 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();
        }      
    }
         
}

Note:

  • @Singleton – probably the most important line of code in this class. This annotation specifies that there will be exactly one singleton of this type of bean in the application. This bean can be invoked concurrently by multiple threads. It comes also with a @PostConstruct annotation. This annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization – in our case is to initialize the MongoClient
  • the @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) declares a singleton session bean’s concurrency management type. By default it is set to Container, I use it here only to highlight its existence. The other option ConcurrencyManagementType.BEAN specifies that the bean developer is responsible for managing concurrent access to the bean instance.
  • the @Lock(LockType.READ) specifies the concurrency lock type for singleton beans with container-managed concurrency. When set to LockType.READ, it enforces the method to permit full concurrent access to it (assuming no write locks are held). This permits several threads to access the same MongoClient instance and take advantage of the internal pool of connections to the database. This is VERY IMPORTANT, because the other more conservative option @Lock(LockType.WRITE), is the DEFAULT and enforces exclusive access to the bean instance. This should make the method slower in a highly concurrent environment…

Use the @Singleton EJB

Now that you have the MongoClient “persisted” in the application, you can inject the MongoClientProvider to access the MongoDB (to get the collection names for example):

Access MongoClient from other beans example

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;
    }
     
}

Note: The db object will be a connection to a MongoDB server for the specified database. With it, you can do further operations.  I encourage you to read the Getting Started with Java Driver for more on that…

Be aware

One aspect to bear mind:

“For every request to the DB (find, insert, etc) the Java thread will obtain a connection from the pool, execute the operation, and release the connection. This means the connection (socket) used may be different each time.

Additionally in the case of a replica set with slaveOk option turned on, the read operations will be distributed evenly across all slaves. This means that within the same thread, a write followed by a read may be sent to different servers (master then slave). In turn the read operation may not see the data just written since replication is asynchronous. If you want to ensure complete consistency in a “session” (maybe an http request), you would want the driver to use the same socket, which you can achieve by using a “consistent request”. Call requestStart() before your operations and requestDone() to release the connection back to the pool:

Ensuring complete consistency in a

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

DB and DBCollection are completely thread safe. In fact, they are cached so you get the same instance no matter what.” [3]

Resources

  1. Java MongoDB Driver
  2. Getting Started with Java Driver
  3. Java Driver Concurrency
  4. GitHub – mongodb / mongo-java-driver examples
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Adrian Matei

Adrian Matei (ama [AT] codingpedia DOT org) is the founder of Podcastpedia.org and Codingpedia.org, computer science engineer, husband, father, curious and passionate about science, computers, software, education, economics, social equity, philosophy.
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button