Getting Stale Connection using OracleDataSource with OCI driver - java

I am getting stale connection error when there is no requests to the database from my java application for couple of hours.
Its a simple java application runned on Linux box with OCI (type driver). Dont ask me why OCI, why not thin. I am using OracleDataSource and OracleConnectionCacheManager for maintaining the cache of connection objects. Here is the code snippet:
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import oracle.jdbc.pool.OracleConnectionCacheManager;
import oracle.jdbc.pool.OracleDataSource;
import org.apache.log4j.Logger;
import com.exception.DataException;
public class ConnectionManager {
private static OracleDataSource poolDataSource = null;
private final static String CACHE_NAME = "CONNECTION_POOL_CACHE";
private static OracleConnectionCacheManager occm = null;
public static void init(String url,String userId,String password) throws PCTDataException{
Properties cacheProps = null;
try {
poolDataSource = new OracleDataSource();
poolDataSource.setURL(url);
poolDataSource.setUser(userId);
poolDataSource.setPassword(password);
cacheProps = new Properties();
cacheProps.setProperty("MinLimit", "1");
cacheProps.setProperty("MaxLimit", "5");
cacheProps.setProperty("InitialLimit", "1");
cacheProps.setProperty("ValidateConnection", "true");
poolDataSource.setConnectionCachingEnabled(true);
occm = OracleConnectionCacheManager.getConnectionCacheManagerInstance();
occm.createCache(CACHE_NAME, poolDataSource, cacheProps);
occm.enableCache(CACHE_NAME);
} catch (SQLException se) {
throw new DataException("SQL Exception while initializing connection pool");
}catch(Exception e){
throw new DataException("Exception while initializing connection pool");
}
}
public static Connection getConnection() throws PCTDataException {
try{
if (poolDataSource == null) {
throw new SQLException("OracleDataSource is null.");
}
occm.refreshCache(CACHE_NAME, OracleConnectionCacheManager.REFRESH_INVALID_CONNECTIONS);
Connection connection = poolDataSource.getConnection();
return connection;
}catch(SQLException se){
se.printStackTrace();
throw new DataException("Exception while getting Connection object");
}catch(Exception e){
e.printStackTrace();
throw new DataException("Exception while getting Connection object");
}
}
public static void closePooledConnections() {
try{
if (poolDataSource != null) {
poolDataSource.close();
}
}catch(SQLException se){
}catch(Exception e){
}
}
}
The error is as follows:
ConnectionManager.java:getConnection:87 - Exception while getting Connection object:
java.sql.SQLException: Invalid or Stale Connection found in the Connection Cache
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.pool.OracleImplicitConnectionCache.getConnection(OracleImplicitConnectionCache.java:390)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:404)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:189)
What am I missing?

Maybe you need to set keep alives on? what this does is periodically, when not in use it send a ping to the database server basically saying I am still here and don't close me out. This is not that fun to try to debug though. The problem could be a setting on your database server where there is a max connection age, or a time to kill idle connections. There also could be some settings in your pool that you could use to that would check for this and then just tell it to get a new one when this happens. I wish I could be more help but I have not worked with oracle.

Instead of using OracleDataSource + OracleConnectionCacheManager, I would recommend using the OracleOCIConnectionPool, which was specifically designed for caching OCI connections.
It is a drop in replacement for OracleDataSource, except the PoolConfig properties for OracleDataSource and the OracleOCIConnectionPool are a bit different.

You will get the "Invalid or Stale Connection" error when you have a connection in the connection pool which is no longer connected to the Database actively. Below are few scenarios which can lead to this
Connection is manually aborted from the database by a dba. For example, if
the connection was killed using "ALTER SYSTEM KILL SESSION"
When a connection exists in the connection pool without being used for a
long time and is disconnected due to the timeouts enforced by the
database (idle_time)
A database restart
A network event has caused
the connection to drop, probably because the network has become
unavailable or a firewall has dropped a connection which has been
open for too long.
Run the below query to determine the IDLE_TIME enforced by the Database
select * from dba_profiles dp, dba_users du
where dp.profile = du.profile and du.username ='YOUR_JDBC_USER_NAME';
Now try with the below configuration
Properties cacheProps = new Properties();
cacheProps.setProperty("MinLimit", "0");
cacheProps.setProperty("MaxLimit", "5");
cacheProps.setProperty("InitialLimit", "1");
cacheProps.setProperty("ValidateConnection", "true");
cacheProps.setProperty("InactivityTimeout", "17000"); //something lower than the DB IDLE_TIME
cacheProps.setProperty("PropertyCheckInterval", "16000") /*something lower than the inactivity timeout
- to make sure that connections which were inactive for more than InactivityTimeout
are always removed from the pool*/

Related

Tomcat doesn't sync with the mysql database

I'm currently working on a college project, and I'm creating a very simple e-commerce style website.
I'm using JDBC driver manager and connection pool for the connection to the db, while using Tomcat 9.0 as the container.
The problem is: when I modify some product through the website (let's say the amount available for example), the website doesn't always reflect the changes, while I can always see the data correctly in MySql Workbench.
It actually works one time out of two on the same query:
I run the query for the first time after the changes -> it shows the old value
I run the query for the second time after the changes -> it shows the new value
I run the query for the third time after the changes -> it shows the old value
And so on.
I've already tried to set caching off (from the query, using the SQL_NO_CACHE), but it didn't seem to solve the problem, I've tried to use Datasource instead, but it causes other problems that most likely I won't have the time to solve.
This is the connection pool file, which I think might be problem, I'm not that sure tho:
public class DriverManagerConnectionPool {
private static List<Connection> freeDbConnections;
static {
freeDbConnections = new LinkedList<Connection>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("DB driver not found:"+ e.getMessage());
}
}
private static synchronized Connection createDBConnection() throws SQLException {
Connection newConnection = null;
String ip = "localhost";
String port = "3306";
String db = "storage";
String username = "root";
String password = "1234";
newConnection = DriverManager.getConnection("jdbc:mysql://"+ ip+":"+ port+"/"+db+"?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC", username, password);
newConnection.setAutoCommit(false);
return newConnection;
}
public static synchronized Connection getConnection() throws SQLException {
Connection connection;
if (!freeDbConnections.isEmpty()) {
connection = (Connection) freeDbConnections.get(0);
freeDbConnections.remove(0);
try {
if (connection.isClosed())
connection = getConnection();
} catch (SQLException e) {
connection.close();
connection = getConnection();
}
} else {
connection = createDBConnection();
}
return connection;
}
public static synchronized void releaseConnection(Connection connection) throws SQLException {
if(connection != null) freeDbConnections.add(connection);
}
}
I really hope you can help me, I haven't found any solution online!
I guess it is because of auto-commit is disabled. Please try using #Transactional or set auto-commit to true. You can also try to use db.commit after each statement.
As per your connection pool implementation, all connection in your pool seems to be auto committed false.
Please check you have properly committed the connection after executing the query or not.
So it might be the case that, when executing the query after changes with same connection it reflects those changes, done earlier and on other connections, old values are might get returned.

Database connection stops after period of time for no apparent reason

I deployed my first Java web application a couple of days ago and realized a strange thing was happening. After a period of time all the dynamic content and functionality that relied on a connection to my database (testimonial submission, admin login) stopped working. It seems like this is happening every 24 hours or so. Every morning I realize it isn't working again.
I solve the issue by going in to the Tomcat web application manager and clicking "reload" on the web app in question. Immediately the dynamic features of the website work again.
My server is running Tomcat 7 and MySQL and the web app uses the JDBC driver to establish the connection to the database. I've made no alterations to Apache or Tomcat settings.
I have other web apps written in PHP that work persistently without fault it just seems to be this Java web app that has this problem.
What would cause this to happen and how can I make it so the web app doesn't need to be reloaded before it can establish a database connection again?
EDIT: attached some code for database connection
Database connection
public class DBConnection {
private static Connection conn;
private static final Configuration conf = new Configuration();
private static final String dbDriver = conf.getDbDriver();
private static final String dbHostName = conf.getDbHostname();
private static final String dbDatabaseName = conf.getDbDatabaseName();
private static final String dbUsername = conf.getDbUsername();
private static final String dbPassword = conf.getDbPassword();
public Connection getConnection(){
try{
Class.forName(dbDriver);
Connection conn = (Connection) DriverManager.getConnection(dbHostName + dbDatabaseName, dbUsername, dbPassword);
return conn;
} catch(Exception e){
e.printStackTrace();
}
return conn;
}
public void disconnect(){
try{
conn.close();
} catch (Exception e){}
}
}
Controller for login form:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String form = request.getParameter("form");
// check login details
if(form.equals("loginForm")){
String username = request.getParameter("username").trim();
String password = request.getParameter("password").trim();
password = loginService.hashPassword(password);
boolean isValidUser = loginService.checkUser(username, password);
if(isValidUser){
Cookie loggedIn = new Cookie("loggedIn", "true");
loggedIn.setMaxAge(60*60*24);
response.addCookie(loggedIn);
out.print("success");
}else{
out.print("nope");
}
}
}
Login service checks login details are correct:
public boolean checkUser(String username, String password){
boolean isValid = false;
try{
sql = "SELECT username, password FROM morleys_user WHERE username=? AND password=? AND isActive=1 LIMIT 1";
prep = conn.prepareStatement(sql);
prep.setString(1, username);
prep.setString(2, password);
rs = prep.executeQuery();
if(rs.next()){
return true;
}
}catch(Exception e){
e.printStackTrace();
}finally{
connection.disconnect();
}
return isValid;
}
UPDATE
If I understand correctly I should not be handling a direct connection to a database and instead be using a service that will manage connections for me.
This is my example of establishing a DataSource connection to a MysQL database.
Establish a new DataSource instance of this class:
package uk.co.morleys;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
public class DataSourceFactory {
public static DataSource getMySQLDataSource() {
Properties props = new Properties();
FileInputStream fis = null;
MysqlDataSource mysqlDS = null;
try {
fis = new FileInputStream("db.properties");
props.load(fis);
mysqlDS = new MysqlDataSource();
mysqlDS.setURL(props.getProperty("MYSQL_DB_URL"));
mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME"));
mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));
} catch (IOException e) {
e.printStackTrace();
}
return mysqlDS;
}
}
Instantiating a new DataSource for checking user login details
public boolean checkUser(String username, String password){
boolean isValid = false;
DataSource ds = DataSourceFactory.getMySQLDataSource();
Connection con = null;
ResultSet rs = null;
PreparedStatement ps = null;
try{
con = ds.getConnection();
sql = "SELECT username, password FROM morleys_user WHERE username=? AND password=? AND isActive=1 LIMIT ";
ps = con.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
rs = ps.executeQuery();
if(rs.next()){
return true;
}
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(ps != null) ps.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return isValid;
}
Given that you've never heard of a connection pool before I'm assuming that you not are not very effectively managing database resources.
The most basic way to access the database is to obtain a connection, execute some statements & close the connection.
In the code you provided I don't see you obtaining or closing a connection, so I assume that you create a single connection when you start your application and keep the connection open "forever". After a certain amount of time your MySql server decides to kill the connection as it's been open for too long.
When you create and close a connection each time you need one, you normally won't encounter any connection timeouts, but you might experience a lot overhead from creating a connection each time your application needs one.
This is where a connection pool comes in; a connection pool manages a number of database connections and your application borrows one each time it needs one. By properly configuring your connection pool the pool will normally transparently take care of broken connections (you might for example configure the pool to renew a connection once it's x minutes/hours old).
You also need to pay attention to resource management; e.g. close a statement as soon as you no longer need it.
The following code demonstrates how your "check user" method can be improved:
public boolean checkUser(String username, String password) throws SQLException {
//acquire a java.sql.DataSource; the DataSource is typically a connection pool that's set-up in the application of obtained via jndi
DataSource dataSource = acquireDataSource();
//java 7 try-with-resources statement is used to make sure that resources are properly closed
//obtain a connection from the pool. Upon closing the connection we return it to the pool
try (Connection connection = dataSource.getConnection()) {
//release resources associated with the PreparedStatement as soon as we no longer need it.
try(PreparedStatement ps = connection.prepareStatement("SELECT username, password FROM morleys_user WHERE username=? AND password=? AND isActive=1 LIMIT 1");){
ps.setString(1, username);
ps.setString(2, password);
ResultSet resultSet = ps.executeQuery();
return resultSet.next();
}
}
}
Common connections pools are Apache Commons-DBCP and C3P0.
As managing sql resources can be quite repetitive and cumbersome you might want to consider using a template: for example Spring's JdbcTemplate
Example C3p0 configuration:
public ComboPooledDataSource dataSource(String driver, String url, String username,String password) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setAcquireIncrement(1);
dataSource.setMaxPoolSize(100);
dataSource.setMinPoolSize(1);
dataSource.setInitialPoolSize(1);
dataSource.setMaxIdleTime(300);
dataSource.setMaxConnectionAge(36000);
dataSource.setAcquireRetryAttempts(5);
dataSource.setAcquireRetryDelay(2000);
dataSource.setBreakAfterAcquireFailure(false);
dataSource.setCheckoutTimeout(30000);
dataSource.setPreferredTestQuery("SELECT 1");
dataSource.setIdleConnectionTestPeriod(60);
return dataSource;
}//in order to do a "clean" shutdown you should call datasource.close() when shutting down your web app.
MySQL times out the connection after some period of time. The standard way to deal with this is to use a properly configured connection pool (with a configured DataSource) instead of using DriverManager directly.
The connection pool will check for and discard "stale" connections.

How to use connection pooling

I am new in connection pooling.I have a created a connection pool in mysql that adds five connections.Now i want to know what is the application of connection pooling,i.e after creating that pool how to use that.. i am pasting my code here
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;
import com.mysql.jdbc.Connection;
class ConnectionPoolManager {
String databaseUrl = "jdbc:mysql://localhost:3306/homeland";
String userName = "root";
String password = "root";
Vector connectionPool = new Vector();
public ConnectionPoolManager() {
initialize();
}
public ConnectionPoolManager(
// String databaseName,
String databaseUrl, String userName, String password) {
this.databaseUrl = databaseUrl;
this.userName = userName;
this.password = password;
initialize();
}
private void initialize() {
// Here we can initialize all the information that we need
initializeConnectionPool();
}
private void initializeConnectionPool() {
while (!checkIfConnectionPoolIsFull()) {
System.out
.println("Connection Pool is NOT full. Proceeding with adding new connections");
// Adding new connection instance until the pool is full
connectionPool.addElement(createNewConnectionForPool());
}
System.out.println("Connection Pool is full.");
}
private synchronized boolean checkIfConnectionPoolIsFull() {
final int MAX_POOL_SIZE = 5;
// Check if the pool size
if (connectionPool.size() < 5) {
return false;
}
return true;
}
// Creating a connection
private Connection createNewConnectionForPool() {
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = (Connection) DriverManager.getConnection(databaseUrl,
userName, password);
System.out.println("Connection: " + connection);
} catch (SQLException sqle) {
System.err.println("SQLException: " + sqle);
return null;
} catch (ClassNotFoundException cnfe) {
System.err.println("ClassNotFoundException: " + cnfe);
return null;
}
return connection;
}
public synchronized Connection getConnectionFromPool() {
Connection connection = null;
// Check if there is a connection available. There are times when all
// the connections in the pool may be used up
if (connectionPool.size() > 0) {
connection = (Connection) connectionPool.firstElement();
connectionPool.removeElementAt(0);
}
// Giving away the connection from the connection pool
return connection;
}
public synchronized void returnConnectionToPool(Connection connection) {
// Adding the connection from the client back to the connection pool
connectionPool.addElement(connection);
}
public static void main(String args[]) {
new ConnectionPoolManager();
}
}
can any one help?
The purpose of connection pooling is to maintain a number of open connections to a database so that when your application requires a connection it does not have to go through the potentially resource and time intensive process of opening a new connection.
When an application requires a database connection it 'borrows' one from the pool. When it's done, it gives it back and that connection may be reused at some later point.
Once you have obtained a connection, you use it in your application through the JDBC (Java Database Connectivity) API.
Oracle's basic tutorial for using JDBC can be found at http://docs.oracle.com/javase/tutorial/jdbc/basics/index.html
Another thing to keep in mind is that alot of work has gone into developing connection pools already, and it probably is not necessary to reinvent the wheel, except perhaps as a learning excercise. Apache Tomcat's connection pool implementation can be used outside of Tomcat (for example, in a standalone Java application) and is fairly flexible and easy to configure. It can be found at https://people.apache.org/~fhanik/jdbc-pool/jdbc-pool.html
I would say the code is pretty self explanatory.
You create an instance of the pool, personally, I prefer to use a singleton, but that's another topic
ConnectionPoolManager connectionPoolManager = new ConnectionPoolManager();
Now, every body that wants a connection, is going to need a reference to this manager. When you need to, you request a free connection from the pool...
public void queryDatabaseForStuff(ConnectionPoolManager cpm) throws SQLException {
Connection con = cpm.getConnectionFromPool();
//....
Once you're finished with the connection, you pass it back to the manager...
try {
//...
} finally {
cmp.returnConnectionToPool(con);
}
Now. You might like to investigating a blocking process that will block the current call to getConnectionFromPool while the pool is empty, meaning that it will either throw an exception (if you want to include a time out feature) or a valid connection.
When re-pooling a Connection, you might like to check to see if the Connection has been closed or not and have some kind of revival process to ensure that the pool is awlays close to capcaity...
Please check this link for getting detailed answer - https://examples.javacodegeeks.com/core-java/sql/jdbc-connection-pool-example/
You don't need to recreate your Connection object pool , instead please use the libraries provided by Apache . Please be clear of the following :
1 - Why and what made you think of connection pool ?
2 - Use the following Apache commons-dbcp lib in your Maven project and then use the classes as per documentation .
3. Does this solve all your problems ?
ITs Better to perform the connection pooling via in built API
Like
DBCP or this.
Its always better let these API perform the connection pooling and programmatically creating and maintaining the connection pooling always painful activity.

Java Postgres connection limit exceeded

I am using Java 1.7 and Postgres via the Postgres JDBC drivers. The database connection will be used from a Web Service. In testing, I got the following error:
FATAL: connection limit exceeded for non-superusers
I solved the error by making my connection static, and, only creating once. My question is, is a static connection safe? Is this the right way to do this?
I am using the connection via a ConnectionFactory that looks something like this:
public class ConnectionFactory
{
String driverClassName = "org.postgresql.Driver";
String connectionUrl = "jdbc:postgresql://localhost:5432/dbName";
String dbUser = "user";
String dbPwd = "password";
private static ConnectionFactory connectionFactory = null;
private static Connection conn = null;
private ConnectionFactory()
{
try
{
Class.forName(driverClassName);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
public Connection getConnection() throws SQLException
{
if (conn == null)
{
conn = DriverManager.getConnection(connectionUrl, dbUser, dbPwd);
}
return conn;
}
public static ConnectionFactory getInstance()
{
if (connectionFactory == null)
{
connectionFactory = new ConnectionFactory();
}
return connectionFactory;
}
}
Postgres JDBC driver is documented as thread safe and the connection can be used by multiple threads if so required. If a thread attempts to use the connection while another one is using it, it will wait until the other thread has finished its current operation.
Connection pooling may be used anyway for performance reasons.
Sorry, original post didn't look at your code carefully. Wow. I still can't read. Anyway, third time's the charm. If your code is single threaded - then your fine. If it's multi-threaded, use something like the Commons connection pools to manage your connections. It looks like the driver is thread safe but the connection shouldn't be viewed as thread safe. So, once the driver is loaded you can safely call getConnection on the driver from multiple threads, but the connection shouldn't be shared across threads.

Custom java.sql.Driver Implementation Connection Handling

Currently, I load the below custom driver (TestDriver.java), get a connection, create a Statement, execute a query, gets the results and close the connection. I open and close a connection for each query. Is this common practice or is there an standard way to share the open connections?
public static void main(String[] args) {
Class.forName("com.sql.TestDriver");
java.sql.Connection conn = DriverManager.getConnection("jdbc:test://8888/connectme", props);
Statement stmt = conn.createStatement;
ResultSet rs = stmt.executeQuery("select * from table");
//loop through rs and pull out needed data
conn.close();
}
public class TestDriver implements java.sql.Driver{
private final TestSchema schema;
private Properties props = null;
static {
try {
DriverManager.registerDriver(new TestDriver());
} catch (SQLException e) {
e.printStackTrace();
}
protected TestDriver() throws SQLException {
schema = TestSchemaFactory.getInstance().getDbSchemaFromFile(SCHEMA_FILE);
//loads in and parses a file containing tables, columns used for business logic
}
public Connection connect(String url, Properties info)
throws SQLException {
TestSqlConnection conn=null;
//connect logic here
return conn; //will return an instance of TestSqlConnection
}
#Override
public boolean jdbcCompliant() {
return false;
}
}
Yes, it's more common to use a database connection pool. This will allow connections to be reused without the overhead or closing/re-opening. Here's a link to DBCP which is one implementation of a database connection pool: http://commons.apache.org/dbcp/
Ideally you should write a separate factory class (can be static)
say ConnectionFactory which returns a connection object.
Also I see that you are not using try/catch/finally block while creating
connection.I strongly suggest to close the connection in finally
clause otherwise you program may suffer from connection leak if any
exception is raised and causes abrupt behavior.
Ideally you should close the connection after your operation is complete in finally
clause.In web based application if you are using connections pool
then closing connection will return the connection back to pool and
will be available for use.

Categories

Resources