Pattern for JDNI datasource - java

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.

Related

Generic Object Name to access datasource connection manager MBean in Liberty

I am trying to access DataSource ConnectionManager MBean using java client.I am able to access it when I specify the datasource name and JNDI name in Object Name.I need a generic approach which can be applicabe for any datasource in server.xml, since this is done as part of a framework that can be used in any application.
I tried multiple options but all the time I got 'javax.management.InstanceNotFoundException'.
Sample code is as given below:
<library id="oracle-lib">
<fileset dir="lib" includes="ojdbc6.jar"/>
</library>
<dataSource jndiName="jdbc/db" id="oracleDB" type="javax.sql.DataSource">
<jdbcDriver javax.sql.DataSource="oracle.jdbc.pool.OracleConnectionPoolDataSource" libraryRef="oracle-lib" />
<connectionManager agedTimeout="10" maxIdleTime="1800" connectionTimeout="180" minPoolSize="10" maxPoolSize="1" reapTime="180"/>
<properties.oracle user="user" password="password"
url="jdbc:oracle:thin:#//db-server:1521/db"/>
</dataSource>
Object name that worked:
ObjectName jvmQuery = new ObjectName("WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/db,name=dataSource[oracleDB]/ConnectionManager[default-0]")
Generic Object Names I tried:
1.WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,*
2.WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,name=dataSource[default-0]/ConnectionManager[default-0],*
3.WebSphere:service=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,*
4.WebSphere:service=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,name=dataSource[default-0]/ConnectionManager[default-0],*
5.WebSphere:service=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,name=dataSource[default-0]/ConnectionManager[default-0]
Could you please advise..
Thank you,
Biju
Query option #1 should work fine:
WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,*
I just tested it with several data sources in my configuration and got the following:
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/ds1,name=dataSource[ds1]/connectionManager
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/ds2,name=dataSource[ds2]/connectionManager
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/ds3,name=dataSource[ds3]/connectionManager[default-0]
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/XAds,name=dataSource[XAds]/connectionManager
Keep in mind that Connection Manager MBeans are lazily created. If you are expecting to find an mbean in a query, make sure that you have gotten a connection from the data source before. Getting a connection from the data source will force a Connection Manager (and its MBean) to be created.

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.

how to do connection pooling in 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

JNDI path Tomcat vs. Jboss

I have DataSource which is configured on Tomcat 6 in context.xml as MyDataSource.
And I'm fetching it the following way:
DataSource dataSource;
try {
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/MyDataSource");
} catch (NamingException e) {
throw new DaoConfigurationException(
"DataSource '" + url + "' is missing in JNDI.", e);
}
Everything works fine. Now I'm exporting this code to Jboss AP 6. and I configured my dataSource and its connection pool as local-tx dataSource under the same name.
When I'm executing the code above, I'm getting NamingException exception. after some investigation I've found that correct way to call my DataSource under Jboss is
dataSource = (DataSource) new InitialContext().lookup("java:/MyDataSource");
Can anybody explain me why should I omit "comp/env" in my JNDI path under Jboss?
The portable approach for defining data sources is to use a resource reference. Resource references enable you to define the JNDI name for your data source, relative to your application naming context (java:comp/env), and then map that logical reference to the physical resource defined in the application server, whose JNDI name is proprietary to the application server vendor. This approach enables your code and assembly to be portable to any compliant application server.
Step 1: Declare and Lookup Resource Reference
Option 1
This can be done by declaring a resource-ref in your web deployment descriptor (WEB-INF/web.xml):
<resource-ref>
<description>My Data Source.</description>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Within your code, you can then lookup this resource using the JNDI name java:comp/env/jdbc/MyDataSource:
dataSource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/MyDataSource");
This JNDI name will not change regardless of the server where the application is deployed.
Option 2
Alternatively, starting in Java EE 5 (Servlet 2.5), this can be done even easier within your code using the #Resource annotation. This eliminates the need for configuring the resource-ref in your web deployment descriptor (web.xml) and prevents the need to perform an explicit JNDI lookup:
public class MyServlet extends HttpServlet {
#Resource(name = "jdbc/MyDataSource")
private DataSource dataSource;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// dataSource may be accessed directly here since the container will automatically
// inject an instance of the data source when the servlet is initialized
}
This approach has the same results as the previous option, but cuts down on the boilerplate code and configuration in your assembly.
Step 2: Map Resource Reference to Data Source
Then, you will need to use your application server's proprietary approach for mapping the resource reference to the physical data source that you created on the server, for example, using JBoss's custom deployment descriptors (WEB-INF/jboss-web.xml):
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<resource-ref>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<jndi-name>java:/MyDataSource</jndi-name>
</resource-ref>
</jboss-web>
Or, for example, using Tomcat's context.xml:
<Resource name="jdbc/MyDataSource" . . . />
You can add to your data source definition the 'jndi-name' tag:
jndi-name - the JNDI name under which the DataSource should be bound.
You can find data source documentation on JBoss wiki: ConfigDataSources

Jboss AP6 Transaction Manager Implementation

I'm just starting to learn Jboss AP6 and I have a few questions:
I created Local Tx Datasource (MySql Database)and can access it in my code using JNDI.
Now I would like to create kind of Transaction Management resource inside of my Jboss AP.
1) Is there any JTA feature built in Jboss AP6?
2) Can I apply it to my local DataSource which I created?
3) Can you please point me to any documentation which explains how to configure it and use it in my code, ot is there any article which coversthese topics in depth?
I googled it for some period of time, but haven't found any useful documentation. I don't want to use Spring/Hibernate out of the box solution just Mysql and plain JTA.
JBoss AP6 support JTA 1.1
Yes you can
If you declareLocalTxDatasource, this is mean, than whenever you get
connection from this datasource this connection will participate in "current" transaction.
If you want to manupulate transaction yourself, without EJB for example, you must enject TransactionManager from JNDI.
Example
TransactionManager tm = (TransactionManager)context.lookup("java:/TransactionManager");
tm.begin();
try{
DataSource ds = context.lookup("java:/testDS");
connection = ds.getConnection()
//do useful work
connection.close();
tm.commit();
}catch(Exception e){
tm.rollback()
}

Categories