Issue on opening MongoDB Connections after calling close Method - java

I am working on a web project using java with mongoDB as back-end database.To open a connection once and reusing the same for each service contained in the project, i am following the below URL
mongodb open connection issue .For closing the connections which are opened, i'm using the function MongoDBClass.INSTANCE.close(); during the user logout of the session in web site.But the problem is, once the user login the session again it produces the following error java.lang.IllegalStateException: state should be: open.That means the connection is not opened , MongoDBClass INSTANCE is not reinitialized so MongoClient is not reopening the connection.But after the server restarts login works perfectly for first time. How to build a new connection again after when i call close method during logout the session of user without restarting the server. I am using the following code
public enum MongoDBClass {
INSTANCE;
private static final String MONGO_DB_HOST = "hostURL";
private Mongo mongoObject;
private DB someDB;
String DB_NAME = null;
MongoClientOptions options = null;
MongoDBClass() {
options = MongoClientOptions.builder().connectionsPerHost(100)
.readPreference(ReadPreference.secondaryPreferred()).build();
mongoObject = new MongoClient(new ServerAddress(MONGO_DB_HOST, 27001),
options);
someDB = mongoObject.getDB(Nutans_Mongo.getNameOFDB());}}
public DB getSomeDB() {
return someDB;
}
public void setSomeDB(String dbName) {
someDB = mongoObject.getDB(dbName);
DB_NAME = dbName;
}
public String close() {
mongoObject.close();
return "true";
}
}

MongoClient maintains a connection pool internally so there is no need to open/close a client for each request. Also, Java enums are not meant to be used this way. Any state an enum has should be globally usable as there will only be one instance of a enum value per ClassLoader/VM. When you call close(), you're globally closing that enum's MongoClient. Since you open the connection in the constructor it never gets reopened because a another INSTANCE is never created.
There are several approaches to ensuring a singleton-like lifecycle of objects in a servlet context. Using CDI to create and inject a MongoClient in to your servlet is one way. Using a ServletContextListener and static field is another, if slightly less savory, approach.

I have the same problem. I'm using the Mongo Java driver 3.0.0.
I upgraded my database from 2.4 to 2.6. But the problem persists.
When I don't close the connection, next time it connects successfully, but in this case open connections raises quickly.

Related

how to get one JDBC Connection for one user in application, if I have 50 users

I am creating a jdbc connection in web application.suppose ,50 users will use the application. currently, my application taking more than 20 connection for single user. how to improve the performance?
public class AuditConnection
{
private static String URL =
"jdbc:postgresql://localhost:5432/MDM_Audit?
user=rajan&password=rajan";
private static String driverName = "org.postgresql.Driver";
private static Connection con;
public static Connection getConnection() {
try {
Class.forName(driverName);
try {
con = DriverManager.getConnection(URL);
} catch (SQLException ex) {
System.out.println("Failed to create the database connection.");
}
} catch (ClassNotFoundException ex) {
// log an exception. for example:
System.out.println("Driver not found.");
}
return con;
}
}
Session & Context
In a web app, you should not be thinking about one database connection per user. Defining “user” in a web app is a bit amorphous. A user could be using multiple browser tabs/windows, or even multiple browsers. The user could be starting and closing sessions, or sessions could be expiring, and the user reconnecting.
Instead, think in terms of:
SessionEach time a user accesses your web app in a browser tab/window, a session is launched. The Java Servlet environment is built to handle the technical details on your behalf, handing you a HttpSession object. The session is closed when the user closes the browser tab/window, or after a time-out of inactivity, or when you programmatically close it, or when the Servlet container determines a problem such as failed network connection.
Each session includes a key-value store of “attributes” where you can keep objects scoped for this session.
ContextThe word “context” is Servlet-speak for your entire web app at runtime. The context is established before the first user request is processed, and is closed after the last response is sent.
On the ServletContext object you will find a key-store of “attributes” similar to the session’s attributes store.
The Servlet spec defines hooks into the lifecycle of both the session and context.
The hook for the context lifecycle is to write a class that implements ServletContextListener. You implement a pair of methods, one called by the Servlet container before the first user connection is handled (your web app is launching), and the other called after the last response is sent out (your web app is shutting-down). Search Stack Overflow for much existing coverage of this topic.
DataSource
Rather than establishing connections as you show there, it is generally better to use a DataSource object.
The JDBC driver from jdbc.postgresql.org provides an implementation of DataSource. See this Question for details: Produce a DataSource object for Postgres JDBC, programmatically.
One benefit of using the DataSource interface is that if you ever change to using a different JDBC driver (such as the pgjdbc-ng driver for Postgres), you need not change any of your calls to getConnection littered throughout your codebase.
The context starting-up hook discussed above is an ideal place for you to load your driver, test a connection to the database, and configure a DataSource object. Store that DataSource object in the “attributes” key-value store on the ServletContext mentioned above.
When you need a connection, access the ServletContext object to retrieve the DataSource your stored there as an attribute. Call DataSource::getConnection to obtain a Connection for your database.
Be sure to close the Connection object when finished with it. Learn to use the try-with-resources feature to make this closing chore a bit more elegant and easy in your code.
Connection pooling
Many people will suggest using connection-pooling. The theory here is that obtaining a connection is relatively expensive, taking a significant amount of time and CPU cycles.
Without pooling, we get a fresh connection to the database, do a bit of limited work, and then close and discard that connection. The Connection object goes out of scope and becomes a candidate for garbage-collection. On the database side, the process that was established by the Postgres Postmaster to handle that connection is closed, and memory freed-up. When a new connection is requested, the Postmaster must go to the bother of setting up a new process and allocating memory in the host OS.
With pooling, a bunch of existing database connections are held open, waiting to be used. When your app needs database work done, a connection is retrieved from the pool, you do your work, and then when you think you are closing the connection, the pool actually intervenes to keep that connection open and at the ready for future use. So every interaction with the database no longer means creating and destroying a connection with the database server.
If you go this route, the work you did above to use DataSource pays off. You switch from using a fresh-connection-each-time implementation of the DataSource interface with a connection-pooling implementation of the interface. So none of your code using the database need change.
Personally, I no longer use database connection pooling. Experiments of mine showed the premise of expensive connections to be exaggerated. Another problem: you must worry about connections being left in proper connection. For example, no pending transactions left open. Yet another problem: Trying to decide on a connection pooling implementation. There have been several over the years, and all have had various issues and problems, thereby inspiring yet another implementation. The upshot: The risk-benefit ratio of pooling is not good enough in my judgement.
You can keep the Connection opened without closing
Use Connection Pooling
(or)
Or you can save the connection object in the session and retrieve it in the servlet and pass it to the function in your DAO class whenever needed.

RESOURCE_EXHAUSTED No session available in the pool

I am using the Spanner client library for Java and i configure the client using Spring.
After a while, the application start to log the following message but i don't understand why. The application concurrency is minimal. It's seem the sessions aren't reused. Any suggestions ?
RESOURCE_EXHAUSTED: No session available in the pool. Maximum number
of sessions in the pool can be overridden by invoking
SessionPoolOptions#Builder#setMaxSessions. Client can be made to block
rather than fail by setting
SessionPoolOptions#Builder#setBlockIfPoolExhausted.
#Configuration
public class SpannerConfig {
#Value("${datasource.instanceId}")
private String instance;
#Value("${datasource.databaseId}")
private String database;
#Bean
public Spanner spannerService() throws IOException {
SessionPoolOptions sessionPoolOptions = SessionPoolOptions.newBuilder()
.setFailIfPoolExhausted()
.setMinSessions(5)
.setMaxSessions(100)
.build();
SpannerOptions options = SpannerOptions.newBuilder()
.setSessionPoolOption(sessionPoolOptions)
.build();
return options.getService();
}
#Bean
public DatabaseClient spannerClient(Spanner spannerService) {
DatabaseId databaseId = DatabaseId.of(spannerService.getOptions().getProjectId(), instance, database);
return spannerService.getDatabaseClient(databaseId);
}
}
It sounds like you have a session leak. Make sure that you're using a try-with-resources expression around any DatabaseClient.singleUse* or DatabaseClient.ReadOnlyTransaction calls to ensure that the Transaction or ResultSet gets closed, allowing the corresponding session to be returned to the session pool.
you are setting .setMaxSessions(100) which obviously does exceed the predefined limit.
in principle, when one client already has allocated 100, the next client can only allocate 0.
the documentation for the sessions reads:
Note: The Cloud Spanner client libraries manage sessions automatically.
... after reading into the source code, I'm sure that the error message is only thrown when using .setFailIfPoolExhausted(). that it reports an exhausted pool, might possibly be a bug, in case StackDriver monitoring tells the opposite.

Spring boot dynamic database URL based on REST parameters

I am using Spring boot to develop an application, we have one database for each customer, and the main problem is to avoid creating one instance for each, connected to a single database. With that in mind, I got stuck in the following situation:
I need my application to make connections to several different databases, witch Aliases I don't know when the application starts. Those aliases will be provided via REST requests, so it's dynamic.
All other credentials are equal on the databases, the Driver, URL, username and password, I really just need to change the alias to provide the right URL for that request.
I've done it creating datasources at the momment of the request, like this:
private static void selectAll(String alias){
String sql = "select * from user";
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url("jdbc:postgresql://localhost:5432/"+alias);
dataSourceBuilder.username("username");
dataSourceBuilder.password("password");
DataSource dataSource = dataSourceBuilder.build();
try {
Connection con = dataSource.getConnection();
con.setAutoCommit(true);
con.prepareStatement(sql).executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
}
But by doing things that way, i can't use criteria and hibernate, and I have to map my objects retreived from the database by hand and write my own simple SQLs for each object/table.
The main question is, can i use Entities and Repositories (Spring data) with dynamic databases, or if I go for this I'll have to choose between those and having one instance for each customer, connected to a single database.
I've searched on forums, and the solutions are eigther based on static connections, configured inside Application.properties, or they assume that the the URL is known.
Thank you for your help, any other better aproaches are wellcome, any toughts at all.

How to get ServletContext attribute from a java class (not servlet)

Good evening! I have a web app with login-logout, where you can buy or sell some products. My queries are stored in a java class, called DBManager, which has just static methods that are called from servlets (I can't use JSP because in this project we can't use them, the professor gives us this constraint).
So here's the problem: I used to manage connection with ServletContextListener. In contextInitialized I set up connection, and in contextDestroyed I shutdown it. The attribute "Connection" is stored using ServletContext.setAttribute(Connection).
How can i get this parameter through the java class (not servlet) DBManager? I must get the object using getServletContext() inside a servlet and than passing it as an attribute, or there's a shortcut to avoid that?
Opening a connection in the method contextInitialized and closing it in contextDestroyed is a bad solution. Imagine that your web site has two visitors at the same time. They would now share the same database connection. If you work with transactions, you would end up with unexpected results where one visitor commits an intermediate state of a transaction executed by the other visitor. And if the connection is ever lost (maybe because the DB server is restarted), your application will fail because it does not re-establish the connection (unless you have a very smart JDBC driver).
A very expensive but safe solution would be to open a new connection for every database operation, and close it again immediately after the operation.
For a perfect solution, you would use some kind of connection pool. Whenever you need to execute a database statement (or a sequence of statements), you would borrow a connection from the pool. Once you're finished, you would return the connection to the pool. Most pool implementations take care of things like validation (check whether the connection is still "alive"), and multiple threads (different HTTP requests send by different visitors at the same time) can execute statements in parallel.
If you want to go for this solution, maybe the Commons DbUtils library is something for you: http://commons.apache.org/dbutils/
Or you check out the documentation of your Java application server or servlet engine (Tomcat?) to see what built-in DB connection pooling features it provides.
Instead of arbitrary getting the connection, you could change your class to receive a connection. That allows you to pass any instance of connection (what happens if you need to get data from another database?).
Also, imagine that the code will be ported to desktop. With this approach you can reuse your DAO without any changes.
class DBManager {
private Connection connection;
public DBManager(Connection connection) {
this.connection = connection;
}
//methods that will use the connection
}
In your HttpServlet doPost or doGet methods you can call getServletContext().
ServletContext sc = getServletContext();
DataSource ds = (DataSource) sc.getAttribute("ds");
Connection conn = ds.getConnection();
A servlet can bind an object attribute into the context by name. Any attribute bound into a context is available to any other servlet that is part of the same Web application.
Context attributes are LOCAL to the JVM in which they were created. This prevents ServletContext attributes from being a shared memory store in a distributed container. When information needs to be shared between servlets running in a distributed environment, the information should be placed into a session, stored in a database, or set in an Enterprise JavaBeans component.

JDBC/Connectorj: When to load drivers?

I was wondering what is the 'correct' way to load drivers for my Java servlet.
Currently, I have a InitializeDrivers() function that I call at the beginning of my application.
public static boolean InitializeDrivers()
{
try {
Class.forName("com.mysql.jdbc.Driver");
return true;
} catch (ClassNotFoundException ex) {
// log error
return false;
}
}
After that is done, I go on performing my various requests/inserts to the database depending on the HTTP request that was received. However, since my servlet can receive hundreds of requests per seconds, InitializeDrivers() will be called one time for each request.
Is it the correct way to do this, or is there a way to load the drivers only once?
When you're using a database in a servlet, then it is better to let the servlet container manage database connections through a connection pool instead of directly getting a database connection yourself in the servlet.
Opening a connection to a database server is a relatively slow operation. Also, the number of connections that a database can handle at the same time is limited. Your application will be slow and not very scalable when you open a database connection each time you need to access the database. Also, database connections are not thread-safe, so you cannot store a database connection in a static member variable of the servlet and use that every time.
A connection pool manages a number of open connections for you (so that you don't have to open the connection each time you need to access the database), and manages the number of connections that are open at the same time. In for example Apache Tomcat, you can configure this so that you lookup a javax.sql.DataSource object via JNDI, which you then use to get a Connection object from.
This page explains how to configure Tomcat and use a DataSource in your servlet:
JNDI Datasource HOW-TO
If you do not want to do this and you want to continue using database connections from your servlet (which I do not recommend), then you could load the driver in a static initializer block in your servlet:
public class MyServlet extends HttpServlet {
static {
Class.forName("com.mysql.jdbc.Driver");
}
// ...
}
Note that in JDBC 4.0, loading the driver explicitly is not necessary anymore; JDBC will automatically find drivers as long as they in the classpath.

Categories

Resources