Understanding Apache Tomcat Connection Pooling - java

I am trying to implement Apache Tomcat's built-in JDBC connection pool. But I am confused with many things.
There are 2 methods mentioned in official page to initialize connection pool.
One using JNDI lookup and another by java PoolProperty class.
For JNDI lookup, we have to add entry to context.xmlor server.xml and initilize it in the java code. This require database connection details to be hardcoded.
For pool properties, we have to set various connection attributes in PoolProperty class using the datasource object. Does it require instantiating factory? (org.apache.tomcat.jdbc.pool.DataSourceFactory)
Whenever a try using pool properties, I am getting the error:
SEVERE: Unable to create initial connections of pool.
java.sql.SQLException: invalid arguments in call at
oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
I checked and confirmed all properties are correct. This error goes once I use the xml method. Can someone help me the correct way to configure pooling without xml?
This standalone java code gives me error:
PoolProperties p = new PoolProperties();
String dburl="jdbc:oracle:thin:#(DESCRIPTION=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=hostname) (PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=shostname2)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=Service)))";
p.setUrl(dburl);
p.setDriverClassName("oracle.jdbc.OracleDriver");
p.setUsername(username);
p.setPassword(pwd);
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1 from dual");
p.setTestOnReturn(false);
p.setValidationInterval(30000);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMaxActive(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(600);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
p.setJdbcInterceptors(
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
+ "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;"
+ "org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer");
p.setLogValidationErrors(true); datasource = new org.apache.tomcat.jdbc.pool.DataSource( );
datasource.setPoolProperties(p);
When I add A global Resource to Server.xml as below,it is working.
Resource auth="Container" description="User database that can be
updated and saved"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
name="jdbc/database" type="javax.sql.DataSource"/>
Please Help me to understand, what's the correct way of implementation.

Related

Oracle UCP sql exception Cannot get Connection to Datasource

I am trying to integrate UCP and tomcat and i have made the configuration correct as given in the oracle docs but still something is missing and while connecting I am getting the following exception
java.sql.SQLException: Unable to start the Universal Connection Pool: oracle.ucp
.UniversalConnectionPoolException: Cannot get Connection from Datasource
I have all jar files in my lib folder and context.xml defined but still need to know where I am going wrong or something i am missing following is the code which is throwing exception
pds=PoolDataSourceFactory.getPoolDataSource();
// Setting connection parameters
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setURL("jdbc:oracle:thin:#//localhost:1521:xe");
pds.setUser("hr");
pds.setPassword("hr"); // till here working fine
// setting pool properties
pds.setInitialPoolSize(5); // throws above mentioned Exception
pds.setMinPoolSize(5);
pds.setMaxPoolSize(15);
System.out.println("Creating pool /// debug 4");
System.out.println("Creating pool .... finish");

JDBC transactions - Tomcat 7.0 and vFabric tc differences

Everyone.
I am working on some Java servlet with JDBC access to PostgreSQL DB. Application is using DataSource defined as resource in server's context. DataSource has auto commit property set to "false" - I am managing transactions from servlet.
In application I have following code:
String query =
"insert into auth_selling_permissions "
+ "(selling_permissions_key, "
+ "sell "
+ ") values ( "
+ " DEFAULT, "
+ PermissionLevel.getIntegerValue(org.getSell())+") "
+ " returning selling_permissions_key";
List<Map<String,Object>> list = this.template.queryForList(query);
Integer outKey = (Integer)list.get(0).get("selling_permissions_key");
Within same transaction I am doing the following action:
for(Map<String,Object> prod : listProducts){
Integer k = (Integer)prod.get("type_key");
keysSection+="("+outKey+", "+k+"),";
}
if(keysSection.length()>0){
keysSection = keysSection.substring(0, keysSection.length()-1);
String bindingQuery = "insert into auth_selling_products_permissions (selling_permissions_key, type_key) values "+keysSection;
this.template.update(bindingQuery);
}
Code above is meant to insert a row to selling_permission table, get back newly generated key and, using it, fill related table (which uses selling_permission_key as FK).
As I mentioned, all is done within single transaction.
The problem is: I am using for developement STS with vFabric tc server. In dev environment it works great. But production env. uses Tomcat 7.0. When I am runnin my servlet on Tomcat 7 (using same database server, same JDBC driver and same definition of db resource) - it fails. It gives me org.springframework.dao.DataIntegrityViolationException and tells that key, which I am trying to insert into auth_selling_products_permissions does not exist in auth_selling_permissions.
I am quite sure that the problem is on server level. But I have now idea why Tomcat behaves like that, and what should I check/configure/change to make it work as my dev tc server.
EDIT:
Resource definition:
<Resource name="jdbc/calc_webapp" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="dbuser" password="password" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/prod_db" defaultAutoCommit = "false"/>
Exactly the same on both servers.

Need to dynamically create a data source for MySQL Connect/J connection pool

I have an application that needs to use connection pool when connection to the database. Problem is, the application is designed to configure and change the connection settings on the fly. I have written the following code that will allow me to dynamically create the data source and then use that to open the connections to the database. However, this code was written for the DataDirect driver and I have used it to connect to Oracle and MS SQL. Unfortunately, the DataDirect Mysql driver will only connect to the commercial version of mysql, not the free version. So now I am attempting to accomplish the same task with connect/j from mysql. I cannot find how to set the connection properties found in a external (static) datasource definition via method calls like for the DD driver. Any help would be appreciated.
BaseDataSource bds = (BaseDataSource)ds;
// Populate the DataSource
bds.setDescription("Driver Data Source");
bds.setServerName(connectUrl);
bds.setUser(userName);
bds.setPassword(password);
if ( spyAttr.length() > 0 ) bds.setSpyAttributes(spyAttr);
// Create the PooledConnection DataSource. Pass the data source created above
// to the PooledConnection DataSource
pds = new PooledConnectionDataSource();
pds.setDescription("Pooled Data Source");
pds.setDataSourceName("myDataSource", bds);
pds.setPoolName("myPool");
pds.setInitialPoolSize(nPoolSize);
pds.setMinPoolSize(minPoolSize);
pds.setMaxPoolSize(maxPoolSize);
pds.setPropertyCycle(propCycle);
pds.setMaxIdleTime(maxIdleTime);
pds.setTracing(tracing);
// Get connection
pds.getConnection();
Apparently the MySQL Connector/J driver doesn't allow those parameters to be passed in with method calls so you will have to pass them in as parameters in the URL (jdbc:mysql://localhost/test?user=foo&password=bar).

Call to DataSource.getConnection not returning the expected connection

I have the following code:
Hashtable env1 = new Hashtable();
env1.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory");
log.info("Executed step 1");
env1.put(javax.naming.Context.PROVIDER_URL, "iiop://myhost.com:9301");
log.info("Executed step 2");
Context ctx = new InitialContext(env1);
DataSource ds = (DataSource)ctx.lookup("jdbc/mydatasource");
log.info("Excecuted lookup ="+ds);
conn = ds.getConnection();
I have the previous code in an standalone application that is connecting to WAS 6.1.0.3 in order to retrieve a connection from the datasource. The code is very straighforward, and I have seen the same code working in a different environment, but in this case when I call getConnection I get an exception. The datasource is WAS has the proper authentication alias set and when the connection is tested it works OK from the WAS side, but the previous code won't work.
If I change this line: conn = ds.getConnection();
to this: conn = ds.getConnection("username","password");
Then the code will work! But that's not what I want since the connections in the datasource should already have the credentials set. I was initially thinking this was a Sybase problem, but it's also happening with Oracle, so would rather say I have a problem with WAS.
If you are curious about the exceptions, for Sybase I get:
java.sql.SQLException: JZ004: User name property missing in DriverManager.getConnection(..., Properties).DSRA0010E: SQL State = JZ004, Error Code = 0
at com.sybase.jdbc2.jdbc.ErrorMessage.raiseError(ErrorMessage.java:569)
at com.sybase.jdbc2.tds.LoginToken.<init>(LoginToken.java:128)
at com.sybase.jdbc2.tds.Tds.doLogin(Tds.java:506)
at com.sybase.jdbc2.tds.Tds.login(Tds.java:449)
at com.sybase.jdbc2.jdbc.SybConnection.tryLogin(SybConnection.java:254)
at com.sybase.jdbc2.jdbc.SybConnection.regularConnect(SybConnection.java:230)
at com.sybase.jdbc2.jdbc.SybConnection.<init>(SybConnection.java:200)
at com.sybase.jdbc2.jdbc.SybPooledConnection.<init>(SybPooledConnection.java:72)
at com.sybase.jdbc2.jdbc.SybConnectionPoolDataSource.createConnection(SybConnectionPoolDataSource.java:138)
at com.sybase.jdbc2.jdbc.SybDriver.connect(SybDriver.java:485)
at com.sybase.jdbc2.jdbc.SybDriver.connect(SybDriver.java:517)
at com.sybase.jdbc2.jdbc.SybDataSource.getConnection(SybDataSource.java:227)
at com.sybase.jdbc2.jdbc.SybConnectionPoolDataSource.getPooledConnection(SybConnectionPoolDataSource.java:74)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper$1.run(InternalGenericDataStoreHelper.java:897)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper.getPooledConnection(InternalGenericDataStoreHelper.java:892)
at com.ibm.ws.rsadapter.spi.WSRdbDataSource.getPooledConnection(WSRdbDataSource.java:1181)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.createManagedConnection(WSManagedConnectionFactoryImpl.java:1047)
at com.ibm.ws.rsadapter.spi.WSDefaultConnectionManagerImpl.allocateConnection(WSDefaultConnectionManagerImpl.java:81)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:431)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:400)
And for Oracle I get this one:
java.sql.SQLException: invalid arguments in callDSRA0010E: SQL State = null, Error Code = 17,433
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:236)
at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:420)
at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSource.java:297)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:221)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPhysicalConnection(OracleConnectionPoolDataSource.java:157)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPooledConnection(OracleConnectionPoolDataSource.java:94)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPooledConnection(OracleConnectionPoolDataSource.java:75)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper$1.run(InternalGenericDataStoreHelper.java:897)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper.getPooledConnection(InternalGenericDataStoreHelper.java:892)
at com.ibm.ws.rsadapter.spi.WSRdbDataSource.getPooledConnection(WSRdbDataSource.java:1181)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.createManagedConnection(WSManagedConnectionFactoryImpl.java:1047)
at com.ibm.ws.rsadapter.spi.WSDefaultConnectionManagerImpl.allocateConnection(WSDefaultConnectionManagerImpl.java:81)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:431)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:400)
In both cases I won't the exception if I pass the credentials to the getConnection method
Thanks for your advice.
Short answer: external clients don't get to use the authentication alias data
Longer Answer:
From the WAS J2C connection factory documentation:
The alias that you configure for component-managed authentication does not apply to all clients that must access the secured resource. External Java clients with Java Naming and Directory Interface (JNDI) access can look up a Java 2 Connector (J2C) resource such as a data source or Java Message Service (JMS) queue. However, they are not permitted to take advantage of the component-managed authentication alias defined on the resource. This alias is the default value that is used when the getConnection() method does not specify any authentication data, like user and password, or a value for ConnectionSpec. If an external client needs to get a connection, it must assume responsibility for the authentication by passing it through arguments on the getConnection() call.
It's been a long time since I've done anything with WebSFEAR^H^H^H^Hphere, but it looks to me that you have a configuration problem. There was a special screen where you'd create credentials (user/pass) and later you'd apply those credentials to the created data source. It looks like that your configured data source hasn't got credentials applied.
Even after defining the user/password values as custom properties I found that the connections for Oracle weren't working. After many days, I just found that the development server is running an old WAS 6.1 version, the problem I'm having was fixed in WAS 6.1.0.5: PK32838: J2CA0046E WHEN USING USING CUSTOM PROP PASSWORD ON DATASOURECE
I tried my code in a different WAS server with an updated WAS fix pack level and... it worked without introducing a single change in the code or in the configuration. So the solution is to upgrade the WAS server.
Thanks.

How do you configure a DataSource in Java to connect to MS SQL Server?

I'm trying to follow Java's JDBC tutorials to write a Java program that can connect to SQL Server 2008. I'm getting lost at the point of making a connection.
The following snippet is from the tutorial:
InitialContext ic = new InitialContext();
DataSource ds = ic.lookup("java:comp/env/jdbc/myDB");
Connection con = ds.getConnection();
DataSource ds = (DataSource) org.apache.derby.jdbc.ClientDataSource()
ds.setPort(1527);
ds.setHost("localhost");
ds.setUser("APP")
ds.setPassword("APP");
Connection con = ds.getConnection();
There's no explanation of what comp/env/jdbc/myDB should point to, and I don't know how I should choose a port. Also, the object ds seems to be defined twice.
I'm using the JSQLDataSource driver, for the record. Can anyone point me in the right direction here?
http://java.sun.com/docs/books/tutorial/jdbc/basics/connecting.html
I'm not sure anyone above has really answered the question.
I found this microsoft sample useful.
The key information in there is really that the class you need is SQLServerDataSource
that is basically a configuration object - you use it something like this:
SQLServerDataSource dataSource = new SQLServerDataSource();
dataSource.setUser("aUser");
dataSource.setPassword("password");
dataSource.setServerName("hostname");
dataSource.setDatabaseName("db");
You would then call
dataSource.getConnection();
to get a connection object which is basically the thing you use to talk to the database.
Use
connection.prepareStatement("some sql with ? substitutions");
to make something for firing off sql and:
connection.prepareCall
for calling stored procedures.
Start with the JDBC tutorial or the Microsoft docs.
and this:
String driver = "com.microsoft.jdbc.sqlserver.SQLServerDriver";
Class.forName(driver);
String url = "jdbc:microsoft:sqlserver://host:1433/database";
Connection conn = DriverManager.getConnection(url, "username", "password");
Fill in your values for host, database, username, and password. The default port for SQL server is 1433.
UPDATE: Good point below. JDBC drivers can be had from both Microsoft and jTDS. I prefer the latter.
JNDI lookups have to do with Java EE app servers that support connection pooling. You can ask the app server to create a pool of connections, which can be an expensive thing to do, and loan them out to clients like library books as needed.
If you aren't using a Java EE app server or connection pooling, you have to create the connection on your own. That's where manual processes and DriverManager come in.
EXPLANATION: As for why the Sun tutorial shows DataSource twice, I'd say it's a case of poor editing. If you look above the code sample it says you can get a DataSource "by lookup or manually". The code snippet below shows both together, when it should be one or the other.
You know it's an inadvertent error because there's no way the code as written could compile. You have "ds" declared twice.
So it should read "...lookup", followed by its code snippet, and then "...manually", followed by its code snippet.
I like the jTDS driver for connecting to SQL Server. A URL will look like this:
jdbc:jtds:sqlserver://localhost/Finance;instance=sqlexpress
Check this for jTDS Url Info.
This also has some interesting information to help troubleshoot jtds to sql express sorts of problems.
DataSource ds = new SimpleDriverDataSource(new com.mysql.jdbc.Driver(),
"jdbc:mysql://database:1433;databaseName=name", "username", "password");
JdbcTemplate jdbc = new JdbcTemplate(ds);
This question has already been answered long time ago. The question was asked about JNDI lookup. With lookup you have to see the application server log to see what the connection is bound to. For example in Jboss startup, I can see:
[ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=myDB' to JNDI name 'java:myDB'
Using that name=myDB you lookup
InitialContext ic = new InitialContext();
DataSource ds = ic.lookup("java:myDB");
Notice how the server log and the code both point to the JNDI name java:myDB.

Categories

Resources