Currently I'm using a separate DBConnectionManager class to handle my connection pooling, but I also realized that this was the wrong way to go as the servlet was not calling the same pool each time a doGet() is performed.
Can someone explain to me why the above is happening?
Is JNDI the way to go for java servlets with tomcat for proper connection pooling?
I have links to 2 articles, is this the correct way to implement connection pooling with servlets?
http://www.javaranch.com/journal/200601/JDBCConnectionPooling.html
http://onjava.com/onjava/2006/04/19/database-connection-pooling-with-tomcat.html
Is it possible to save the db manager object in the context like so:
mtdb = (MTDbManager) context.getAttribute("MTDBMANAGER");
if (mtdb == null) {
System.out
.println("MTDbManager is null, reinitialize MTDbManager");
initMTDB(config);
context.setAttribute("MTDBMANAGER", mtdb);
}
And then I call mtdb.getInstance().getConnection() and it will always reference this object.
Thanks.
Generally, the best advice is to leave the connection pooling to the application server. Just look up the data source using JNDI, and let the application server handle the rest. That makes your application portable (different application servers have different pooling mechanisms and settings) and most likely to be most efficient.
Have a look at, and use, C3P0 instead of rolling your own solution: http://sourceforge.net/projects/c3p0/
Related
I've read the documentation and I understand how Propagation.REQUIRES_NEW works but
Create a new transaction, and suspend the current transaction if one exists. Analogous to the EJB transaction attribute of the same name.
NOTE: Actual transaction suspension will not work out-of-the-box on all transaction managers. This in particular applies to org.springframework.transaction.jta.JtaTransactionManager, which requires the javax.transaction.TransactionManager to be made available to it (which is server-specific in standard Java EE).
See Also:
org.springframework.transaction.jta.JtaTransactionManager.setTransactionManager
I can't understand how suspension could work.
For a single level transaction I suppose that spring creates the code like this:
Connection connection = DriverManager.getConnection(...);
try {
connection.setAutoCommit(false);
PreparedStatement firstStatement = connection.prepareStatement(...);
firstStatement.executeUpdate();
PreparedStatement secondStatement = connection.prepareStatement(...);
secondStatement.executeUpdate();
connection.commit();
} catch (Exception e) {
connection.rollback();
}
Could you please provide an example for the Propagation.REQUIRES_NEW?
Is it done somehow via jdbc savepoint?
but I can't understand how suspension could work.
It mostly doesn't.
Is it done somehow via jdbc savepoint ?
JDBC doesn't support the notion of suspending transactions (it supports the notion of subtransactions, though - that's what savepoints are about. JDBC does, that is - many DB engines do not).
So how does it work?
By moving beyond the confines of JDBC. The database needs to support it, and the driver also needs to support it, outside of the JDBC API. So, via a non-JDBC-based DB interaction model, or by sending an SQL command.
For example, In WebLogic, there's the WebLogic TransactionManager. That's not open source, so I have no idea how it works, but the fact that it's a separate API (not JDBC) is rather telling.
It's also telling that the javadoc of JtaTransactionManager says that there are only 2 known implementations, and that these implementations steer quite close to the definitions in JTA.
Straight from that javadoc:
WebSphere-specific PlatformTransactionManager implementation that delegates to a UOWManager instance, obtained from WebSphere's JNDI environment.
So, JNDI then. "Voodoo skip JDBC talk directly to the database magic" indeed.
In my web application I'm using JDBC connectivity basically its working fine with below code
connObj = DriverManager.getConnection(dbaseUrl, usrName, Paswrd);
But when I'm using veracode tool its showing flaw as J2EE Bad Practice:getConnection so that i need to implement.
InitialContext ctx= new InitialContext();
DataSource dsrc=(DataSource)ctx.lookup(dbaseUrl, usrName, Paswrd);
dsrc.getConnection();
How can I pass 3 parameters in lookup so that it should not disturb my previous flow of code. Can anybody guide me please?
You cannot change the lookup method parameter. But you can use bind or rebind methods of InitialContext to retrieve your datasource.See sample
ctx.bind("java:/comp/env/jdbc/nameofmyjdbcresource", dsrc);
For details example check here.
A DataSource is a connection to one database and you configure a DataSource with a single username and password. If you really need specific (and changing) usernames/passwords depending on application logic, then you can use DataSource.getConnection(String username, String password). However keep in mind with some (most?) connection pools this will give you a non-pooled connection.
If you want to access a different database (or a different configuration), then you need to specify a data source for each database you want to access and ask for that specific data source.
If that is not possible for your situation, then you should just ignore/suppress the veracode warning and continue using DriverManager.
I'm currently working on a java application. It's a standalone client with Spring and Hibernate. Also C3P0.
In the previous version we used a standard user(hardcoded in the configuration file) for the database connection but now we changed it so that every user has to provide his own credentials.
The beans with the code for the database are basically created on-demand.
I changed the XML-files and added a postprocessor which sets the credentials as well as some connection settings. It looks similar to this now:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
configurer = new PropertyPlaceholderConfigurer();
// properties are retrieved from a private method
configurer.setProperties(getProperties());
context.addBeanFactoryPostProcessor(configurer);
context.setConfigLocations(new String[] { "first.xml","second.xml" });
context.refresh();
return context.getBean("myClass", MyClass.class);
This all works as expected but now we reach the part where I'm currently stuck.
I want to provide a test functionality for the connection, so that the user can click a button and then is told if his credentials were accepted or not.
My first idea was to do a simple select on the database. Sifting through the logs however, I noticed that Spring tries to connect to the database during the refresh() (or rather the instantiation of the bean) anyway. I can see exceptions in the logs, for example: java.sql.SQLException: Connections could not be acquired from the underlying database!
Unfortunately, Spring doesn't seem to actually care. The exceptions are logged away but refresh() finishes and is not throwing any exceptions because of this. I had hoped that I could simply catch the exception and then I would know that the connection failed.
I could just do the select as planned, but I want to limit the connection attempts as much as possible, because the database server will block the user after several attempts. Even permanently if there are to many attempts(already had some fun with that, before I changed the settings for the connection pool).
My searches regarding this problem came up with practically nothing. Is there a way to get the exception somehow? Or does Spring provide an API of sorts that would tell me about the connection error during the instantiation/refresh?
Failing that, any ideas for an alternative approach? Preferably one that needs only a single attempt to determine if a connection is possible.
Edit: For anyone interested: I went with the suggestion from Santosh and implemented a connection test in JDBC.
Unfortunately there seems to be no easy way to make use of the database errors/exceptions encountered during the bean instantiation.
The kind of functionality you are looking for would be very tricky to accomplish using spring+hibernate.
The connection properties are set at the session-factory level and if credentials are incorrect, the session-factory is not instantiated.
Quoting #Bozo from his answer here.
What you can do is extend LocalSessionFactoryBean and override the
getObject() method, and make it return a proxy (via
java.lang.reflect.Proxy or CGLIB / javassist), in case the
sessionFactory is null. That way a SessionFactory will be injected.
The proxy should hold a reference to a bare SessionFactory, which
would initially be null. Whenever the proxy is asked to connect, if
the sessionFacotry is still null, you call the buildSessionFactory()
(of the LocalSessionFactoryBean) and delegate to it. Otherwise throw
an exception. (Then of course map your new factory bean instead of the
current)
There is also a simple and rudimentary approach wherein before creating ClassPathXmlApplicationContext, simply try to obtain a connection using raw JDBC calls. If that succeed then proceed or else give use appropriate message.
You can limit the connection attempts here as you are in full control.
I'm using spring integration to communicate via active mq. I've got the following config.
<integration:channel id="riskApprovalRequestChannel"/>
<integration:channel id="riskApprovalResponseChannel"/>
<jms:outbound-gateway id="riskApprovalServiceGateway"
request-destination-name="${risk.approval.queue.request}"
reply-destination-name="${risk.approval.queue.response}"
request-channel="riskApprovalRequestChannel"
reply-channel="riskApprovalResponseChannel"
connection-factory="jmsConnectionFactory"
receive-timeout="1000"/>
<integration:gateway id="riskApprovalService" service-interface="com.my.ServiceInterface"
default-request-channel="riskApprovalRequestChannel"
default-reply-channel="riskApprovalResponseChannel"/>
This works well except for the 1st request, which is slow. I always hit the 1 second timeout on the 1st request. There's obviously some lazy loading going on somewhere.
My question is, how do I do a full initialisation at start up to avoid the 1st request always timing out?
Cheers,
Peter
It is probably connection establishment that's the issue.
One thing you can do is wrap the vendor ConnectionFactory in a Spring CachingConnectionFactory (good idea to do this anyway, for performance reasons), and call createConnection() during initialization.
There are a number of ways to do that - including injecting the connection factory into some other bean, with an init-method, #PostConstruct method, or an InitializingBean with afterPropertiesSet(); it will be called during context initialization.
This will cause the cache's connection to be eagerly connected.
You might want to do it in a try block, to avoid the application context failing to initialize because the JMS broker is not available (of course messaging will still fail, but the app will be up and ready to connect when the broker is available).
I want to use pooled connections with Java (because it is costly to create one connection per thread) so I'm using the MysqlConnectionPoolDataSource() object. I'm persisting my data source across threads. So, I'm only using one datasource throughout the application like this:
startRegistry(); // creates an RMI registry for MySQL
MysqlConnectionPoolDataSource dataSource = new MysqlConnectionPoolDataSource();
dataSource.setUser("username");
dataSource.setPassword("password");
dataSource.setServerName("serverIP");
dataSource.setPort(3306);
dataSource.setDatabaseName("dbname");
InitialContext context = createContext(); // Creates a context
context.rebind("MySQLDS", dataSource);
Now that I have my datasource created, I'm doing the following in each separate thread:
PooledConnection connect = dataSource.getPooledConnection();
Connection sqlConnection = connect.getConnection();
Statement state = sqlConnection.createStatement();
ResultSet result = state.executeQuery("select * from someTable");
// Continue processing results
I guess what I'm confused on is the call to dataSource.getPooledConnection();
Is this really fetching a pooled connection? And is this thread safe?
I noticed that PooledConnection has methods like notify() and wait()... meaning that I don't think it is doing what I think it is doing...
Also, when and how should I release the connection?
I'm wondering if it would be more beneficial to roll my own because then I'd be more familiar with everything, but I don't really want to reinvent the wheel in this case :).
Thanks SO
This is not the right way. The datasource needs to be managed by whatever container you're running the application in. The MysqlConnectionPoolDataSource is not a connection pool. It is just a concrete implementation of the javax.sql.DataSource interface. You normally define it in the JNDI context and obtain it from there. Also MySQL itself states it all explicitly in their documentation.
Now, how to use it depends on the purpose of the application. If it is a web application, then you need to refer the JNDI resources documentation of the servletcontainer/appserver in question. If it is for example Tomcat, then you can find it here. If you're running a client application --for which I would highly question the value of a connection pool--, then you need to look for a connection pooling framework which can make use of the MySQL-provided connection pooled datasource, such as C3P0.
The other problem with the code which you posted is that the PooledConnection#getConnection() will return the underlying connection which is thus not a pooled connection. Calling close on it won't return the connection to the pool, but just really close it. The pool has to create a new connection everytime.
Then the threadsafety story, that depends on the real connection pooling framework in question. C3P0 has proven its robustness in years, you don't worry about it as long as you write JDBC code according the standard idiom, i.e. use only the JDBC interfaces and acquire and close all resources (Connection, Statement and ResultSet) in shortest possible scope.