My application-server has a connection to a MySQL database. This connection is open 24/7.
Lets say my internet were to crash, or I were to block the port 3306.
Will JDBC throw an error? And if not, how should I be handling this kind of problem?
The reason I'm asking this is because I've had cases before where the MySQL connection randomly stopped working, but wasn't closed, which caused clients to time out.
You will get a MySQLNonTransientConnectionException or CommunicationsException. Typically, for program safety you either want to:
Open/close connections as necessary
Re-open when connection is closed
I recommend the former personally, especially when the database is user-specified (some mysql setups have a connection timeout).
Edit:
I did seem to forget to mention connection pools, per #ThorbjørnRavnAndersen , but that is also a viable solution. I personally don't do that myself, using an instantiable SQL connection per threaded operation.
Personally, I throw any database calls into try/catch blocks, because there's always the potential for issues to arise. You'll want to set some default values in the catch block, and if it happens to land on these defaults for whatever reason, display the end user some sort of (ideally pretty) error message.
Running a SQL query isn't always guaranteed to pull back any sort of results either...any number of things could go wrong - the server could be down, the connection could be so saturated that it's not able to pull the results in a timely manner, it could be sitting in the dead center of a backup of sorts too....These things have to always be accounted for, that's why I recommend doing it the way described above.
Lastly, to answer your question, yes, JDBC will in fact throw an error - under any of these circumstances.
Related
I have an application which we'll refer to as App.class that checks the database every second for real time events.
I encountered an instance where the database was down and App.class kept on retrying and throwing an exception.
What I want to achieve is to determine whether a valid connection is available or not in real time.
I can get the provider by:
C3P0ConnectionProvider provider = (C3P0ConnectionProvider) sessionFactoryImpl.getConnectionProvider()
and I could check if the connection is closed by doing: provider.getConnection().isClosed().
However, if the database is down and I try to invoke provider.getConnection(), App.class hangs for a bit (probably trying to look for a connection), then throws an exception.
I was wondering if there's an easy way to determine if a connection exists instead of just catching the error/exception when it happens.
So, c3p0 cannot tell you whether a database is "down". Metaphysically, epistemologically, it just has no access to that information. It observes only shadows of the DBMS on the walls of the network.
There are a few thing c3p0 can do for you though:
It can test Connections before giving them to you
It can not leave you hanging
You can ask it in advance whether there are likely to be Connections available without a wait.
It sounds like you have already asked c3p0 to test Connections for you on checkout, either via hibernate.c3p0.validate or c3p0.testConnectionOnCheckout. If you hadn't, you wouldn't see your app hang on getConnection() when the database was down, you'd just see failures when you tried to use the Connection. (You might be testing Connections on check-in and idle. More on that possibility below.)
Rather than putting up with a hang, you could set the config parameter c3p0.checkoutTimeout, so that if c3p0 doesn't have a good Connection to hand you relatively quickly, it sets you free with an Exception.
Ideally, you might prefer to just know in advance whether a good Connection is available before trying to check it out and hanging even briefly. You can ask c3p0 whether Connections are likely to be immediately available, via methods on c3p0's PooledDataSource interface. If you had access to a PooledDataSource pds, you'd just do something like
int idle = pds.getNumIdleConnectionsDefaultUser();
and could know whether a call to getConnection() would be likely to success quickly if there are at least a few idle Connections. (You can't have a guarantee, because c3p0 and hibernate are very asynchronous, so between your check and your checkout attempt, things may change. And no, you can't try to use a synchronized block or something to make these things atomic, c3p0's pools do their locking internally, not at the outer DataSource level.)
But even if there are idle Connections, you won't know if they are good until you test them, and if the DBMS is down, you'll hang as c3p0 tries all of its idle Connections, rejects them, and then waits in vain to try to acquire Connections. What you'd like is for c3p0 to have pre-tested the Connections, so that if none are good, none appear idle.
You can't get that perfectly, but you can come close by replacing connection testing on checkout with connection testing on checking combined with frequent tests of idle Connections. See c3p0's docs for details on how. If you do this, bad Connections will quickly be evicted from the pool, and the idle Connection count will come to approximate the count of idle good Connections. So, you'll have some, albeit imperfect, confidence that, if you see idle Connections, the DBMS is up and a call to getConnection() will succeed quickly. Back that up with a checkoutTimeout for the period when the DBMS has just crashed, but c3p0 hasn't yet detected it, and you'll be pretty close to where you want to be.
Oh, to get the PooledDataSource from a hibernate Connection provider, looking at the source code, should be something like...
import com.mchange.v2.c3p0.PooledDataSource;
PooledDataSource pds = provider.unwrap(PooledDataSource.class);
int idle = pds.getNumIdleConnectionsDefaultUser();
I haven't tried this code, and am writing this in a terrible rush (sorry!), but that should work, if it is worth this much trouble. I think most users just limit the time cost of a database outage using c3p0.checkoutTimeout without going to the trouble to get the PooledDataSource to ask about idle Connections. But if you need that, you can get it.
I am using J2EE and a Mysql database and making a connection using JDBC. I want to know when the database crashes and how to handle it. Is it that the only way to check the database is to see if the connections establish successfully? Or there is other way?
You can't and shouldn't need to know. As far as your program is concerned, either everything works perfectly or you can't get a connection.
The program has to behave correctly if a connection can't be acquired, which in most cases probably involves some form of error display and ceasing of operations. Naturally you'll want to have some form of monitoring so that someone will know to check what's wrong with the database, but it's not your program's responsibility.
There are actually a lot of things that can go wrong in a database that might constitute a crash, a major failure or a partial failure. A table could get dropped by an admin, you could run out of space, etc, etc. These might allow you to get a connection or they might not.
It is probably going to be very difficult to distinguish between what constitutes a major failure (database down) and what is a partial failure that might allow the system to continue.
Obviously, if you can't connect to the database, you can't do much with your application. That might indicate the database has "crashed", but it could also be a network problem if your database in on another server. It doesn't really matter.
Most applications that I have worked on don't do much in terms of checking for major failures. But there are a few of strategies that might help:
Have some "sanity checks" (e.g., query a known table). If the sanity checks fail, you have a critical problem.
Have an error count. If more than a certain number of errors occurred in a given time, you have a critical problem.
How do I know in my Java code when my DB crashes?
As of JDBC 4.1 (JavaSE 7) there is the Connection.setNetworkTimeout(Executor, int) method which make JDBC operations cease execution and throw an SQLException if they take longer than the timeout you set.
To use this mechanism, set the network timeout to a number of milliseconds which you want to be the maximum amount of time you will wait to hear back from the DB. If any operations takes longer than the timeout you set, it will cease waiting and the method will throw an SQLException.
An example of how setNetworkTimeout could be used:
Connection conn = // get your connection however
conn.setNetworkTimeout(Executors.newSingleThreadExecutor(),
10 * 1000); // 10s timeout
Statement stmt = conn.createStatement();
// suppose DB crashes at this point in time
try {
stmt.execute("SOME SQL HERE");
} catch (SQLException sqle) {
// could be from network timeout,
// but could also be caused by something else
// You can check what your JDBC driver does
}
As you can see with this example, the fact that network timeouts only throw a SQLException makes the mechanism harder to work with. I really wish the architects of JDBC 4.1 had decided to require some subclass of SQLException be thrown so that there was a portable way of telling when a network timeout occurs. Something like SQLNetworkTimeoutException as a subclass of SQLException would have been nice.
In any case, your best bet for checking whether or not your SQLException was caused from a network timeout is by checking the message String on the SQLException, but be a bit careful doing this as different JDBC drivers will have different messages for network timeouts.
Another thing you could try in addition to or besides network timeout is checking for SQLNonTransientException. Typically the exception that will occur when there is some sort of catastrophic DB failure is the SQLNonTransientException which is the subclass of SQLException.
Essentially this exception means "something went wrong that is outside of the control of your code or the JDBC driver's". So generally when you see this, it's because of a DB failure or network failure.
How do I handle a DB failure once I know something went wrong?
This part is a bit tricky, especially since so many things can go wrong with a DB (it could have crashed, the network could be down/slow, etc).
Option A: Show that something went wrong
In most cases I've seen, the way to "handle" this sort of failure is to acknowledge it and just present it to the user.
Option B: Retry and/or failover
Another option is doing a fixed number of retries and/or failing over to a backup database. Failing over to a backup db can be tricky, and typically this is only done if you have some sort of middleware do it for you.
I would like to know friends, when a jdbc connection becomes invalid, it could be that it was closed intentionally, or some transaction made it invalid and closed it, is there a way to know what exactly made the connection invalid, is there any trace left on the connection that I can get and check.
I am faced with a situation where I have to detect a server that has gone offline, how I do this is; any operation that tries to borrow a connection from the connection pool, check if that connection is valid. If it is not, and if the reason for it not being valid is that it failed to connect to the database, then fire a propertychange and notify any subscriber to the change, the subscriber will then popup a dialog to block all operations and start querying the database every 5 seconds to check if it is back. Hope I made my situation clear
Better you could use a connection pooling library that will validate connection on behalf of you. During database operation it will automatically test the connection health and make a new connection if the existing one is invalid.
For C3P0 connection pooling library, please check the following document:
http://www.mchange.com/projects/c3p0/#configuring_connection_testing
Typically when you attempt to use a stale connection, for example by issuing a simple SQL statement as suggested by #PeterLawrey, an SQLException will be thrown, containing the details of what is wrong, if they are at all available to the driver. Catch the exception and analyze what is returned by its getErrorCode() and getSQLState() methods. Keep in mind that, while SQLSTATE values are standardized, they are not very granular, while vendor error codes may provide more information but will differ when connected to different database platforms.
I'd like to come up with the best approach for re-connecting to MS SQL Server when connection from JBoss AS 5 to DB is lost temporarily.
For Oracle, I found this SO question: "Is there any way to have the JBoss connection pool reconnect to Oracle when connections go bad?" which says it uses an Oracle specific ping routine and utilizes the valid-connection-checker-class-name property described in JBoss' Configuring Datasources Wiki.
What I'd like to avoid is to have another SQL run every time a connection is pulled from the pool which is what the other property check-valid-connection-sql basically does.
So for now, I'm leaning towards an approach which uses exception-sorter-class-name but I'm not sure whether this is the best approach in the case of MS SQL Server.
Hoping to hear your suggestions on the topic. Thanks!
I am not sure it will work the way you describe it (transparently).
The valid connection checker (this can be either a sql statement in the *ds.xml file or a class that does the lifting) is meant to be called when a connection is taken from the pool, as the db could have closed it while it is in the pool. If the connection is no longer valid,
it is closed and a new one is requested from the DB - this is completely transparent to the application and only happens (as you say) when the connection is taken out of the pool. You can then use that in your application for a long time.
The exception sorter is meant to report to the application if e.g. ORA-0815 is a harmless or bad return code for a SQL statement. If it is a harmless one it is basically swallowed, while for a bad one it is reported to the application as an Exception.
So if you want to use the exception sorter to find bad connections in the pool, you need to be prepared that basically every statement that you fire could throw a stale-connection Exception and you would need to close the connection and try to obtain a new one. This means appropriate changes in your code, which you can of course do.
I think firing a cheap sql statement at the DB every now and then to check if a connection from the pool is still valid is a lot less expensive than doing all this checking 'by hand'.
Btw: while there is the generic connection checker sql that works with all databases, some databases provide another way of testing if the connection is good; Oracle has a special ping command for this, which is used in the special OracleConnectionChecker class you refer to. So it may be that there is something similar for MS-SQL, which is less expensive than a simple SQL statement.
I used successfully background validation properties: background-validation-millis from https://community.jboss.org/wiki/ConfigDataSources
With JBoss 5.1 (I don't know with other versions), you can use
<valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MSSQLValidConnectionChecker</valid-connection-checker-class-name>
What is a Connection Object in JDBC ? How is this Connection maintained(I mean is it a Network connection) ? Are they TCP/IP Connections ? Why is it a costly operation to create a Connection every time ? Why do these connections become stale after sometime and I need to refresh the Pool ? Why can't I use one connection to execute multiple queries ?
These connections are TCP/IP connections. To not have to overhead of creating every time a new connection there are connection pools that expand and shrink dynamically. You can use one connection for multiple queries. I think you mean that you release it to the pool. If you do that you might get back the same connection from the pool. In this case it just doesn't matter if you do one or multiple queries
The cost of a connection is to connect which takes some time. ANd the database prepares some stuff like sessions, etc for every connection. That would have to be done every time. Connections become stale through multiple reasons. The most prominent is a firewall in between. Connection problems could lead to connection resetting or there could be simple timeouts
To add to the other answers:
Yes, you can reuse the same connection for multiple queries. This is even advisable, as creating a new connection is quite expensive.
You can even execute multiple queries concurrently. You just have to use a new java.sql.Statement/PreparedStatement instance for every query. Statements are what JDBC uses to keep track of ongoing queries, so each parallel query needs its own Statement. You can and should reuse Statements for consecutive queries, though.
The answers to your questions is that they are implementation defined. A JDBC connection is an interface that exposes methods. What happens behind the scenes can be anything that delivers the interface. For example, consider the Oracle internal JDBC driver, used for supporting java stored procedures. Simultaneous queries are not only possible on that, they are more or less inevitable, since each request for a new connection returns the one and only connection object. I don't know for sure whether it uses TCP/IP internally but I doubt it.
So you should not assume implementation details, without being clear about precisely which JDBC implementation you are using.
since I cannot comment yet, wil post answer just to comment on Vinegar's answer, situation with setAutoCommit() returning to default state upon returning connection to pool is not mandatory behaviour and should not be taken for granted, also as closing of statements and resultsets; you can read that it should be closed, but if you do not close them, they will be automatically closed with closing of connection. Don't take it for granted, since it will take up on your resources on some versions of jdbc drivers.
We had serious problem on DB2 database on AS400, guys needing transactional isolation were calling connection.setAutoCommit(false) and after finishing job they returned such connection to pool (JNDI) without connection.setAutoCommit(old_state), so when another thread got this connection from pool, inserts and updates have not commited, and nobody could figure out why for a long time...