How to connect to MongoDB from a Java EE stateless application


Codever Logo

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏


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:

<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:

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):

    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:

    DB db...;
    db.requestStart();
    try {
       db.requestEnsureConnection();
    
       code....
    } finally {
       db.requestDone();
    }

    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
    Subscribe to our newsletter for more code resources and news

    Adrian Matei (aka adixchen)

    Adrian Matei (aka adixchen)
    Life force expressing itself as a coding capable human being

    routerLink with query params in Angular html template

    routerLink with query params in Angular html template code snippet Continue reading