I'm writing a program that does some stuff on the database. Users are allowed to configure db processes, by passing db host port, type and credentials. It all works fine when values are correct. But when user passes invalid credentials I would like to show an error. So here is the part where I create my connection pool
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setJdbcUrl( connectionUrl );
cpds.setUser(username);
cpds.setPassword(password);
And later to verify if all is ok with the connection I do
cpds.getConnection()
I would expect to get some SQLException with vendor specific error saying that credentials are invalid (which happens when you use typical DriverManager way of getting the connection), but instead the process waits until a connection checkout exception is thrown
java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:690)
....
Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool#20014b8 -- timeout at awaitAvailable()
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1467)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:644)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:554)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:758)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:685)
... 66 more
How can I identify that there is a invalid credential issue with c3p0?
Your best way to validate provided credentials/JDBC params is to avoid connection pool at all.
Open dedicated connection just for this purpose and try to execute simplest SQL against new connection (eg SELECT 1 or similar).
After success, you can pass them to C3P0 otherwise propagate error back to user.
JDBC providers are free to create whatever error/exception messages they want. So you need to be ready to parse the error message of each provider in order to make sense of what is happening.
You can also try to get information from exception types if the JDBC provider segregates errors in separate types.
As a side note, giving too much information regarding why the connection failed may be considered a security breach. So one should not expect the JDBC driver to give you such information. For instance, why would any database collaborate with invasion attempts by saying "the username is correct, but the password is not."?
Related
I'm currently creating an API server that reads and writes. Using MongoDB
The library uses Mongoose.
I wonder if db.close() must be used when reading and writing.
datamodel.js:
var db = mongoose.connect('mongodb://localhost/testdb', {useNewUrlParser: true,useUnifiedTopology:true});
mongoose.Promise = global.Promise;
.....
Boards = mongoose.model("boards", BoardSchema);
exports.Boards = Boards;
routes/getList.js:
let result = await Boards.find().sort({"date": -1});
Should I close the DB declared above with db.close() when reading or writing?
(Very generic answer, but should help you get started with what to research)
Closing MongoDB connection depends on how is the connection established in the first place.
Are you initialising the connection on server startup: If yes, you should not close the connection. (But initialising the connection on server startup is bad idea because, if connection is lost to server (like database server restart), then you would also have to restart the application or set reconnectTries)
Are you using connection pool: If you are using connection pool, then closing and opening of connections is taken care by Mongoose itself. All you have to do is, release the connection after use, so that, it's available for other requests.
Are you creating connection per request: If yes, then you should close the connection before returning the response or you would quickly run out of available connections at database server.
you can call mongoose.disconnect() to close the connection
My server calls sometimes the MSSQL JDBC CallableStatement.execute() that works with a previously connected connection. Everything is ok while the connection is alive. But if the connection is disconnected somehow (e.g. somebody turn SQL server down) the execute() call throws SQLException. I need to differ between 'connection was dropped' error and any other JDBC error (like table I'm trying to use doesn't exist). Since if I hit the connection error - I need to reconnect. And in any other case I need just to give error message to the user.
SQLException.getSQLState() always returns null and getErrorCode() always returns 0.
Thanks
I am no Java expert but this seems to be mainly based on Java.
You'd need to catch the exception from the .execute() command and query the string to see what the error is, then make a decision on which method to execute next based on that information.
I'm having problems with the connection pool in Tomcat after a database outage.
There's this heartbeat service servlet that won't come back up after a database outage.
I've already tried the standard answer, and beyond, specifically:
Adding to the Resource section in server.xml
validationQuery="select 1 from dual"
testOnBorrow="true"
removeAbandoned="true"
removeAbandonedTimeout="120"
logAbandoned="true"
Trying to close the connection with a check to validity:
if (connection != null && !connection.isValid(10)) {
connection.close();
}
(Resulted in java.sql.SQLException: Connection is closed)
Trying to abort the connection (not sure whether done right)
if (connection != null && !connection.isValid(10)) {
connection.abort();
}
(Resulted in java.lang.NoSuchMethodError: java.sql.Connection.abort(Ljava/util/concurrent/Executor;)V)
Tries 2) and 3) show that indeed the connection is invalid, and it knows it. The question is - how to destroy it?
Tomcat version: 7.0.29
The pool will destroy the invalid connection for you thanks to "testOnBorrow=true" setting (note that the "Abandoned" settings only apply to connections which are not returned to the pool).
So this is how it should go:
servlet borrows connection, does queries and returns connection to the pool.
servlet borrows connection, database crashes, servlet receives all kinds of horrible SQL errors but still returns connection to the pool.
database has restarted
on next heartbeat, servlet borrows connection. Tomcat's pool will "test on borrow", find that the old connection is broken, removes (and closes) connection, tries another, finds that it is also broken, etc, and THEN the pool decides to create a new connection, test it OK and hands it over to the servlet.
servlet receives new valid connection, does queries and returns connection to the pool.
I'm not sure how Tomcat's pool behaves when a "test on borrow" indicates a connection is broken (1): it might not create new connections right away or throw an error when it can't get a valid connection from the pool. But I expect the pool to effectively flush itself and re-populate with new (valid) connection.
(1) That is, if the "test on borrow" is actually done which this post indicates is not the case ...
If the pool does not flush itself, you can try to do this programmatically once you find connections are invalid. I have not tried this before, hopefully you can get it to work. Following method is described here:
Reach into the JNDI context, pull-out the DataSource object, cross your fingers, cast it to org.apache.tomcat.jdbc.pool.DataSource, and call the purge() method.
Alterntively, use JMX and call the purge method via the MBean.
If you experience hanging threads after a database crash, you might have to resort to a work around described in this answer.
If we want to dispose an ill java.sql.connection from Tomcat jdbc connection pool,
we may do this explicitly in the program.
Unwrap it into an org.apache.tomcat.jdbc.pool.PooledConnection, setDiscarded(true)
and close the JDBC connection finally, the ConnectionPool will remove the underlying connection once it has been returned.
(ConnectionPool.returnConnection(....))
PooledConnection pconn = conn.unwrap(PooledConnection.class);
pconn.setDiscarded(true);
conn.close();
I generate an SqlSessionFactory from an SqlSessionFactoryBean, and catch exceptions to determine if it successfully created for a given data-source.
However, I have found that method fails if the database exists, but has no listener. No exception is generated and an exception only occurs later when I actually try create an open session of the SqlSessionFactory.
What's the best way for me to check if I am working with a valid database, accepting normal sessions?
Edit: It doesn't actually appear to be that opening a session throws the exception ... it may only happen at my first actual update/retrieve call.
Many connection pools have a connection validation query option, which can be configured to execute something simple like SELECT 1 (depends on the database, of course) to validate the connection is valid. It's the same premise, though: attempt to execute the query and catch the exception.
If you are already using a connection pool, and it supports such an option, I wonder if this would solve your problem.
The database connection is get like below
public Connection getDBConection(){
Context context = new InitialContext();
DataSource dataSource = (javax.sql.DataSource) context.lookup("java:myDataSource");
Connection conn = dataSource.getConnection();
}
For a userA, is each database request should call getDBConnection() once; but no need to control all request use the same connection?
That is, if userA has three database request, then userA should call getDBConnection() three times, and call Connection.closed() after used in each request?
If the userA call getDBConnection() three times (that is, call dataSource.getConnection() three times), is three connection created? Or it is unknown and controlled by weblogic?
I feel very chaos, is it true that there should be one new connection for one database request? or just call DataSource.getConnection() for each database request and the number of new connection created is controlled by web server, no need to think how many connection is actually created.
Every time you call DataSource.getConnection, the data source will retrieve a connection for you. It should be true that the returned connection is not being actively used by anyone else, but it is not necessarily a brand-new connection.
For example, if you use a connection pool, which is a very common practice, then when you call Connection.close, the connection is not actually closed, but instead returns to a pool of available connections. Then, when you call DataSource.getConnection, the connection pool will see if it has any spare connections lying around that it hasn't already handed out. If so, it will typically test that they haven't gone stale (usually by executing a very quick query against a dummy table). If not, it will return the existing connection to the caller. But if the connection is stale, then the connection pool will retrieve a truly new connection from the underlying database driver, and return that instead.
Typically, connection pools have a maximum number of real connections that they will keep at any one time (say, 50). If your application tries to request more than 50 simultaneous connections, DataSource.getConnection will throw an exception. Or in some implementations, it will block for a while until one becomes available, and then throw an exception after that time expires. For a sample implementation, have a look at Apache Commons DBCP.
Hopefully that answers your question!