To resolve the issue mentioned here.
We are creating and using 2 same JDBC Singleton Connections(Regular, Proxy).
But by doing so we are facing deadlock when we try to use both connections consecutively on same table for doing multiple inserts and updates.
When this happens, I cannot run any queries from the DB tool (Aqua Data Studio) as well.
My assumption is that it waits indefinitely for other connection to release lock.
Note: We are not dealing with multi-threading here.
Issue:
// Auto Commit false
// Singelton
Connection connection = getConnection(); //same
// Auto Commit true
// // Singelton
Connection proxyConnection= getConnection(); //same
PreparedStatement ps = null;
try{
connection.setAutoCommit(false);
//Step 1
String sql = getQuery();
ps = proxyConnection.prepareStatement(sql);
ps.executeUpdate();
.
.
//Step 2
// if I don't execute this step everything works fine.
sql = getTransctionQuery();
ps = connection.prepareStatement(sql);
ps.executeUpdate();
.
.
//Step 3
sql = getQuery();
ps = proxyConnection.prepareStatement(sql);
ps.executeUpdate(); // this line never completes (if Step 2 runs)
}catch(){
connection.rollback(); //Doesn’t rollback step 1 and understandably step 2.
}
finally{
connection.close(); //cleanup code
proxyConnection.close();
}
Question:
How to resolve this issue?
How to make sure different connections, though they are creating using same class loader, won't lock database/table.
Thanks
I'm no expert here but I used to have problems with Oracle DB when running a query and then forgetting to commit (or cancel). So I think that the fact that you didn't commit after step 2 locks the database for the next access.
Related
Need help in JDBC transaction control mechanism in JAVA.
Issue:
There are certain stored procedures in our Sybase DB that needs to be run on Unchained mode. Since we are updating our data on two different databases (unfortunately, both Sybase) we need to be able to rollback all our previous transactions, if there is any failure.
But running with Unchained Mode (Auto commit - on) is not helping us with the rollbacks as some of the SPs have already committed the transactions.
Connection connection = getConnection();
PreparedStatement ps = null;
try{
String sql = getQuery(); // SQL Chained Mode
ps = connection.prepareStatement(sql);
ps.executeUpdate(); //Step 1
.
.
sql = getTransctionQuery(); // SQL Unchained Mode
connection.setAutoCommit(true); //Step 2
ps = connection.prepareStatement(sql);
ps.executeUpdate();
connection.setAutoCommit(false);
.
.
sql = getQuery(); // SQL Chained Mode
ps = connection.prepareStatement(sql);
ps.executeUpdate(); //Step 3 This step fails.
connection.commit();
}catch(){
connection.rollback(); //Doesn’t rollback step 1 and understandably step 2.
}
finally{
connection.close(); //cleanup code
}
We would ideally like to rollback both step 1 and step 2 effectively if 3 fails.
Current Solution:
Our idea is to reinvent the wheel and write our own version of rollback (by deleting inserted records and reverting the updated values, from Java).
Need effective solution
Since this solution is effort intensive and not fool proof we would like to know if there are any other better solutions.
Thanks
You need to perform an explicit BEGIN TRANSACTION statement. Otherwise, every DML is a transaction by itself which you cannot control. Obviously autocommit must be off as well.
I have a wierd behavior in a Java application.
It issues simple queries and modifications to a remote MySQL database. I found that queries, run by executeQuery() work just fine, but inserts or delete to the database run through executeUpdate() will fail.
Ruling out the first thing that comes to mind: the user the app connects with has correct privilledges set up, as the same INSERT run from the same machine, but in DBeaver, will produce the desired modification.
Some code:
Connection creation
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url, user, pass);
Problematic part:
Statement parentIdStatement = connection.createStatement();
String parentQuery = String.format(ProcessDAO.GET_PARENT_ID, parentName);
if (DEBUG_SQL) {
plugin.getLogger().log(Level.INFO, parentQuery);
}
ResultSet result = parentIdStatement.executeQuery(parentQuery);
result.first();
parentId = result.getInt(1);
if (DEBUG_SQL) {
plugin.getLogger().log(Level.INFO, parentId.toString()); // works, expected value
}
Statement createContainerStatement = connection.createStatement();
String containerQuery = String.format(ContainerDAO.CREATE_CONTAINER, parentId, myName);
if (DEBUG_SQL) {
plugin.getLogger().log(Level.INFO, containerQuery); // works when issued through DBeaver
}
createContainerStatement.executeUpdate(containerQuery); // does nothing
"DAOs":
ProcessDAO.GET_PARENT_ID = "SELECT id FROM mon_process WHERE proc_name = '%1$s'";
ContainerDAO.CREATE_CONTAINER = "INSERT INTO mon_container (cont_name, proc_id, cont_expiry, cont_size) VALUES ('%2$s', %1$d, CURRENT_TIMESTAMP(), NULL)";
I suspect this might have to do with my usage of Statement and Connection.
This being a lightweight lightly-used app, I went to simplicity, so no framework, and no specific isntructions regarding transactions or commits.
So, in the end, this code was just fine. It worked today.
To answer the question: where to look first in a similar case (SELECT works but UPDATE / INSERT / DELETE does not)
If rights are not the problem, then there is probably a lock on the table you try to modify. In my case, someone left with an uncommited transaction open.
Proper SQL exceptions logging (which was suboptimal in my case) will help you figure it out.
I want to know if ResultSet can be closed if I didn't close it ? I have a ResultSet is closed exception but I am sure I didn't close the ResultSet anywhere .
What I do exactly is that I use the ResultSet to perform a SELECT query then I use the same ResultSet because it's called by this method :
public Object getValueAt( int row, int column )
throws IllegalStateException {
// ensure database connection is available
if ( !dbConnection.isConnectedToDatabase() )
throw new IllegalStateException( "Not Connected to Database" );
// obtain a value at specified ResultSet row and column
try {
getResultSet().absolute( row + 1 );
return getResultSet().getObject( column + 1 );
} // end try
catch ( SQLException sqlException ) {
System.out.println("Exception from here dude");
sqlException.printStackTrace();
} // end catch
return ""; // if problems, return empty string object
} // end method getValueAt
So , another question : Is there a way to ensure the ResultSet is opened ?
Third question : Maybe the problem because I never close ResultSets .
What's the point of closing ResultSet ?
Edit : That's how statement is being created inside the constructor of a class called DBConnection:
Class.forName(driver);
// connect to database
connection = DriverManager.getConnection(url, username, password);
// create Statement to query database
statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY );
//connection ok
connectedToDatabase=true;
ResultSet is created later whenever I want to execute a statement.
Directly from the docs on ResultSet.close():
Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.
...
Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results.
So, if you closed the Statement that generated your ResultSet is closed, you get that exception.
Another question's answer: you shouldn't read results from a ResultSet like that. Perform the select an read all the data you need from the ResultSet at once, close the connection and then later you can read the fetched data as much as you want. You really shouldn't have an external resource/class calling your getValueAt method, which you expect to still be connected to the database. Connection may be terminated for many other reasons, so that's not the way to go.
Third answer: answered above.
Last answer: releasing resources explicitly, without waiting for it to be closed when Statement is.
In case you have closed any of the following, your ResultSet will be closed automatically:
Statement object.
Connection object.
I am strongly suspecting the connection is being closed. It is a natural tendency to close the database connection once the query is run. While it is a good practice, but may be you are closing the connection even before you have used the ResultSet object inside your TableModel class.
I always close Connections, ResultSets and Statements in finally {} block. In such case I don't have this problem, since this block is always executed (Well, not always, but here it fits). Please refer to this post, I placed skeleton implementation that might be interesting for you.
I am using a MySQL DB and a Java JDBC client to access it.
I have a Table that contains session information. Each session is associated with a SessionToken. This token is a Base64 encoded String of a Hash of some of the session values. It should be unique. And is defined as varchar(50) in the db.
When I try to lookup a session by its token I query the database using an sql statement like this:
select SessionId, ClientIP, PersonId, LastAccessTime, SessionCreateTime from InkaSession where SessionToken like 'exK/Xw0imW/qOtN39uw5bddeeMg='
I have a UnitTest that tests this functionality, and it consistently fails, because the query does not return any Session, even tough, I have just written the session to the DB.
My Unit test does the following:
Create Connection via DriverManager.getConnection
Add a session via Sql Insert query
close the connection
create Connection via DriverManager.getConnection
look for the session via sql select
unit test fails, because nothing found
When I step through this UnitTest with the debugger and copy past the select sql that is about to be sent to the db into a mysql command line, it works fine, and I get the session row back.
I also tried to retrive an older session from the db by asking for an older SessionToken. This works fine as well. It only fails, if I ask for the SessionToken immediately after I inserted it.
All connections are on AutoCommit. Nevertheless I tried to set the Transaction Level to "Read Uncommited". This did not work either.
Has anyone any further suggestions?
This is typically caused by the connection not being committed between insert and select.
Did you basically do the following?
statement.executeUpdate("INSERT INTO session (...) VALUES (...)");
connection.commit();
resultSet = statement.executeQuery("SELECT ... FROM session WHERE ...");
Edit I tried the following SSCCE on MySQL 5.1.30 with Connector/J 5.1.7:
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost/javabase", "root", null);
statement = connection.createStatement();
statement.executeUpdate("INSERT INTO foo (foo) VALUES ('foo')");
resultSet = statement.executeQuery("SELECT id FROM foo WHERE foo = 'foo'");
if (resultSet.next()) {
System.out.println(resultSet.getLong("id"));
} else {
System.out.println("Not inserted?");
}
} finally {
SQLUtil.close(connection, statement, resultSet);
}
}
Works flawlessly. Maybe an issue with your JDBC driver. Try upgrading.
Solved: The two token strings where not identical. One of them had a couple of Zero bytes at the end. (Due to the encrypting and decrypting and padding...) The two strings where visually identical, but MySQL and Java both said, they where not. (And they where right as usual)
What is the best way to set up connection with mysql's jdbc?
And execute simple statement. How to do that?
Thank you.
The basic boilerplate for MySQL/JDBC goes something like this:
Get the connection:
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection("jdbc:mysql://databaseName");
Execute the statement:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * from tableName");
while (rs.next()) {
System.out.println(rs.getString(1));
}
Close the statement and connection:
rs.close();
stmt.close();
conn.close();
You just need to make sure you have the driver installed and/or in your CLASSPATH.
This is the twenty first century - use a JPA (ORM) implementation. But if you insist on going back to the metal (at the risk of down votes) -
There are many ways of getting a JDBC connection from some driver. Using reflection with a hardwired class name is the commonest and perhaps most brain damaged. If you're going to hardwire a class name, you might as well as get the benefits of normal code (compiler catches typos, no extraneous exceptions to deal with, easier to read, explicit dependencies, better tool support, etc).
Also get in to the habit of clearing up resources safely.
So:
public static void main(String[] args) throws SQLException {
Driver driver = new com.mysql.jdbc.Driver();
Connection connection = driver.connect(
"jdbc:mysql://mydatabase",
new java.util.Properties() {{
put("user", "fred");
}}
);
try {
PreparedStatement statement = connection.prepareStatement(
"SELECT insideLeg FROM user WHERE name=?"
);
try {
statement.setString(1, "jim");
ResultSet results = statement.executeQuery();
try {
if (results.next() {
System.out.println("= "+results.getLong(1));
} else {
System.out.println("Missing.");
}
} finally {
results.close();
}
} finally {
statement.close();
}
} finally {
connection.close();
}
}
What a mess! And it doesn't even use transactions yet. Yes, use an ORM. They're very respectable these days.
You wont need to do all that for every single statement. You don't want to go around creating instantiating drivers every time. In particular the execute around idiom is useful.
It depends on your case.
If you simply need to execute some queries from standalone application then you should use single connection like:
Class.forName ("yourDriverName");
Connection cn = DriverManager.getConnection ("db url");
Statement st = cn.createStatement ();
ResultSet rs = st.executeQuery ("select * from foo");
while (rs.next()) {
doSmth ();
}
rs.close ();
st.close ();
cn.close ();
But if you are developing real application (specially web-application) then use DataSource's. Read manual of your DB and Web-server how to configure datasource. DataSource allows you to use connection-pooling - it'll nessecary to increase performance.
Configuring DataSource isn't difficult process.
Here's the sun documentation for creating a JDBC connection. From there it's easy to get access to a Statement object and run some simple SQL.
For production level systems you'll probably also want to create a connection pool.
Use Spring Framework's JDBC abstraction framework - all you need to do is create a context XML file, and use the JDBC template class. Just a few lines of XML + Java code will get you going. The advantage is keeping your connection details out of compiled Java. See:
http://www.springbyexample.org/examples/simple-spring-jdbc-template.html