how to do connection pooling in java? - java

I am trying to understand connection pooling in java, i am using jsp, servlet and tomcat 6 server in my application. I have written the following code in a java class dbconnection.java:
I am using type 4 jdbc connection with oracle 10g EE in windows Xp OS
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class dbconnection {
public Connection con = null;
public Connection getConnection() throws Exception, SQLException
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
con=DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:abc","abc", "abc");
}
catch(Exception e)
{
}
return con;
}
public void removeConnection() throws SQLException
{
con.close();
}
}
Then i am retriving connection in servlet as follows:
try{
dbconnection db= new dbconnection();
Connection con=db.getConnection();
}
catch(Exception e){
}
finally{
db.removeConnection();//removes connection
}
Is it connection pooling or some configuration is required in tomcat server or something else?

A connection pool operates by performing the work of creating connections ahead of time.
In the case of a JDBC connection pool, a pool of Connection objects is created at the time the application server starts. The client can access the connection object in connection pool and return the object to pool once the db work is completed.
Context.xml
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000" username="root" password=""
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/cdcol"/>
//This should be added in the servers context,xml file. For example if you are using apache server then the context.xml will be found in C:\apache-tomcat-6.0.26\conf\Context.xml
web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
//This should be added in the web.xml of the local project. (Not in server's web.xml).
Context ctx=new InitialContext();
Context envContext = (Context)ctx.lookup("java:comp/env");
DataSource ds=(DataSource)envContext.lookup("jdbc/TestDB");//TestDB is the Database Name
con=ds.getConnection();
stmt = con.createStatement();

You can get a third-party library, or you can use the connection pooling your Java EE container (for example, JBoss or WebSphere) provides for you.
To do this, you configure and use a JNDI datasource.
Here are details for Tomcat:
http://people.apache.org/~fhanik/jdbc-pool/jdbc-pool.html
http://www.tomcatexpert.com/blog/2012/01/24/using-tomcat-7-jdbc-connection-pool-production

Connection pooling is the feature available in all major web and application servers. You can find the simple example on configuring with Tomcat. Tomcat Connection Pooling
But if you would like to write your own connection pooling then there are libraries available to write. Apache DBCP

Related

How to switch between two databses, based on user request in Java web application?

I am using Spring restful web services in my project, here I have two categories of users
1) secondary (Student studying class between 6 to 10th)
2) inter (Student studying class between 11th and 12th).
In each URI, we specify the user type, for example see below:
(http://localhost:8080/TestProject/login/secondary/authenticate)
For above request, I need to fetch the data from 'secondary' d.b tables.
Similarly for other user type request, need to communicate with other d.b(Inter).
In 'DAO' class:
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(
getDataSource());
jdbcTemplate.getJdbcOperations().execute(
"SET SCHEMA " + **UriUtils.getSchema()**);
In above UriUtils.getSchema(), method returns the 'DataBase' name.
private DataSource getDataSource() {
String db = UriUtils.getDataBaseName();
DataSource dataSource = null;
try {
InitialContext initialContext = new InitialContext();
Context environmentContext = (Context) initialContext
.lookup("java:comp/env");
dataSource = (DataSource) environmentContext.lookup(db);
} catch (NamingException e) {
logger.error(e.getMessage());
logger.info(db + " resource is not available in server.xml file");
e.printStackTrace();
}
return dataSource;
}
In Tomcat server I configured the connection pooling.
server.xml
<Resource auth="Container" driverClassName="org.postgresql.Driver"
logAbandoned="true" maxActive="20" maxIdle="10" maxWait="-1"
name="secondary" password="admin" removeAbandoned="true"
removeAbandonedTimeout="90" type="javax.sql.DataSource"
url="jdbc:postgresql://localhost:5432/postgres?currentSchema=secondary"
username="postgres" />
<Resource auth="Container" driverClassName="org.postgresql.Driver"
logAbandoned="true" maxActive="20" maxIdle="10" maxWait="-1"
name="inter" password="admin" removeAbandoned="true"
removeAbandonedTimeout="90" type="javax.sql.DataSource"
url="jdbc:postgresql://localhost:5432/postgres?currentSchema=inter"
username="postgres" />
context.xml
<ResourceLink name="secondary" global="secondary"
type="org.postgresql.Driver" />
<ResourceLink name="inter" global="inter"
type="org.postgresql.Driver" />
Is loading the datasource object every time is a good practice ?
Please suggest if any better approach is available.
Is loading the datasource object every time is a good practice ?
NO, IMV.
Define two datasources (secondaryDS, interDS) as spring beans default to singleton, and inject corresponding datasource to JDBCTemplateclass as per your requirement.
You do not loading database every time. Lookup operation is not loading database. It is OK perform lookup on every request. Also I do not see two databases in your sample. You have two data sources over one postgresql database. You can use one data source and perform SET SCHEMA on each client request for schema switching.

Pattern for JDNI datasource

I'm using a JNDI ressource in Tomcat8 for connecting to a MS-SQL database (Azure). Randomly I experience Connection closed exception, eventually preceeded by Connection peer reset events. When this happens, the service is dead (running into Connection closed for every request) and restarting the tomcat (redploying) is the only chance to get it up again.
On my way trying to solve this I double(triple)-checked every method for unclosed connections, I assure that every connection is opened as try-with-ressource.
Currently I'm trying to get a better understanding about JNDI ressources and the connection pooling, I'm asking what is the preferred pattern to implement a service class which is injected into other services. E.g. questions are
Where should the DataSource be allocated by calling ctx.lookup()? On method level or class scope? E.g. when using the hk2 #Service annotation it seems that a service is instantiated only once and not per request. Currently ctx.lookup() is invoced once (in the constructor) and the DataSource is stored in a class field and later on accessed by the methods using this.dataSource. Does this make sense ? Or should the DataSource be retrieved on every request (=method call)
How can I verify the execution of several options of the DataSource, e.g. testOnBorrow and removeAbandoned (see complete configuration below) are executed correctly? There is an option logAbandoned but I can not see anything in my logs. Where should this appear anyhow? Can I somehow specifiy a certain log level for the pool? I only found org.apache.tomcat.jdbc.pool, but this class seems only to be called when creating the pool (at least this is the only moment when logs appear, even on level FINEST).
Are there general patterns which I'm not aware of?
Here my current configuration:
<Resource name="jdbc/mssql"
auth="Container"
type="javax.sql.XADataSource"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
username="***"
password="***"
url="jdbc:sqlserver://***.database.windows.net:1433;database=***;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
removeAbandonedOnBorrow="true"
removeAbandonedTimeout="55"
removeAbandonedOnMaintenance="true"
timeBetweenEvictionRunsMillis="34000"
minEvictableIdleTimeMillis="55000"
logAbandoned="true"
validationQuery="SELECT 1"
validationInterval="34000"
/>
Thx, gapvision
Gapvision, you can check this link - What is the good design pattern for connection pooling?
Probably, you would want to go with the object pool pattern.
Hope this helps !!
I'm asking what is the preferred pattern to implement a service class which is injected into other services.
Try spring data. It is very helpful in organizing resources to access data.
Without spring, without tomcat built-in features, you indeed need create your own singletons to allocate DataSource or ConnectionPool.
Without spring(assuming you build web app for tomcat), you can add to web.xml:
<resource-ref>
<description>H2DB</description>
<res-ref-name>jdbc/project1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
And in context.xml of tomcat:
<Resource name="jdbc/project1" auth="Container" type="javax.sql.DataSource" driverClassName="org.h2.Driver" url="jdbc:h2:tcp://localhost/~/project1" username="sa" password="" maxActive="20" maxIdle="10" maxWait="-1"/>
And then you can lookup data source in each request:
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/project1");
Connection conn = null;
try {
conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO USERS (NAME) VALUES (?)");
ps.setString(1,name);
ps.executeUpdate();
response.getWriter().write("added user "+name);
response.getWriter().write("\n");
} finally {
if (conn!=null) { conn.close(); }
}
Or you can create a singleton class and lookup DataSource once , on start or lazy, as singletons do.
But better try spring data.

how to cast dbcp connection to oracle connection?

I need cast PoolableConnection to OracleConnection in runtime but I don't know how to do it.
becasuse i got classCastException and if all classes extends Connection, can I do it ?
You should just be able to cast to the DBCP specific Connection class and from there retrieve the inner Oracle connection:
import org.apache.commons.dbcp.DelegatingConnection;
DelegatingConnection dc = (DelegatingConnection)conn;
OracleConnection oc = (OracleConnection)pc.getInnermostDelegate();
If you are using Tomcat's built-in copy of DBCP then the import you will need is:
import org.apache.tomcat.dbcp.dbcp.DelegatingConnection;
Or you can use the connection pooling built into the Oracle JDBC driver implementation. This returns an Oracle connection. A simple setup would be:
<Resource auth="Container"
connectionCacheName="CXCACHE"
connectionCacheProperties="{MaxStatementsLimit=5,MinLimit=1, MaxLimit=1, ValidateConnection=true}"
connectionCachingEnabled="true"
description="Oracle Datasource"
factory="oracle.jdbc.pool.OracleDataSourceFactory"
name="jdbc/TestDB"
user="default_user"
password="password"
type="oracle.jdbc.pool.OracleDataSource"
url="jdbc:oracle:thin:#//localhost:1521/orcl"
/>
You can cast only if the object you're casting actually is an instance of the class you're casting it to. If you're getting a ClassCastException that's not the case.
All classes that extend Connection can be cast to a Connection, but not necessarily to each other.

How to get username from connection pool declaration at runtime

My connection pool is declared in context.xml of tomcat server as follows :
<Resource name="jdbc/codesign" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#abc.fjd.com"
username="tiger" password="tiger123" maxActive="30" maxIdle="10"
poolPreparedStatements="true" maxOpenPreparedStatements="100"
validationQuery="SELECT SYSDATE FROM DUAL" maxWait="10000"/>
I am initializing datasource in usual way as :
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
ds = (DataSource) envContext.lookup("jdbc/codesign");
What I want is to access the username ("tiger" in this case) at runtime. I am not seeing any such method in javax.sql.DataSource class. And when I try to get schema from connection using
Connection conn = DataSourceConnectionPool.getConnection()
conn.getSchema();
I get following error :
java.lang.AbstractMethodError: org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.getSchema()
And I get the same error if unwrap the connection first :
conn.unwrap(OracleConnection.class).getSchema()
java.lang.AbstractMethodError: oracle.jdbc.driver.OracleConnection.getSchema()
Is ther a way to get schema name or username from datasource or Connection?
If you are using Tomcat, your DataSoruce implementation is most likely BasicDataSource https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.html
You can cast your ds to BasicDataSource, and access the user by getUsername().
But of course try first to print the db.getClass().getName() to see what is the actual implementation.

Java Oracle connection pooling - Closed Connection exception

This post is intended to be less of a question and more a confirmation that I'm doing things correctly. I've seen many similar posts but I'm not sure I fully understand everything that's been said.
The problem is that, after a certain amount of time, I get an exception when trying to establish a connection to my oracle database. (I'm using Tomcat 6.0 and Spring)
Previously I had the following configuration:
private PoolDataSource poolDataSource = null;
public MainDAOImpl(String url, String username, String password)
throws Exception
{
poolDataSource = PoolDataSourceFactory.getPoolDataSource();
try
{
poolDataSource.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
poolDataSource.setURL(url);
poolDataSource.setUser(username);
poolDataSource.setPassword(password);
}
catch( SQLException e )
{
...
}
}
public List<Object> getValues(String query)
{
Connection connection = null;
PreparedStatement preparedStatement = null;
try
{
connection = poolDataSource.getConnection();
preparedStatement = connection.prepareStatement(query);
...
}
catch( SQLException e )
{
...
}
finally
{
//close connections
}
}
However, sometimes the preparedStatement = connection.prepareStatement(query); threw an SQLException with a "Closed Exception" message.
It's important to note that the MainDAOImpl's constructor gets called only once per server restart (it's dependency injected via Spring).
I've recently changed my setup like so:
private DataSource dataSource = null;
public MainDAOImpl()
throws Exception
{
try
{
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/myOracleConn");
}
catch( NamingException e )
{
...
}
}
and poolDataSource.getConnection() to dataSource.getConnection().
I've also added the following Resource to my Context in Tomcat:
<Resource name="jdbc/myOracleConn" auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.OracleDriver"
url="<myURL>"
username="<myUsername>" password="<myPassword>"
maxActive="20" maxIdle="10" maxWaith="-1" />
This basically follows http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html word-for-word.
Everything seems to be working. My question is, will these changes solve my closed connection problem or is there something different I need to do?
Thanks,
B.J.
First of all, if you are using Spring for dependency injection, I would recommend that you also use DI to inject the DAO's dependencies into it.
In other words, your DAO should have a DataSource injected into it, rather than the DAO implementation knowing either 1) what type of DataSource to construct or 2) how and where to look it up in JNDI. Spring can handle JNDI lookups for you.
I'd also recommend using Spring's JdbcTemplate, as it makes for a great wrapper over raw JDBC calls yourself.
Finally, the actual exception you are getting may just be because the database server is closing long-open connections. Not sure which connection pool implementation you are using, but in commons-dbcp there is an option for a "validationQuery" which the pool will execute before returning a connection to verify the connection is still valid. I'm sure most other pools supply similar features, which I would recommend here - this way your DAO is never receiving stale connections from the pool.

Categories