Според http://docs .oracle.com/javase/7/docs/api/java/sql/Connection.html#close() :
Този тест, използващ Mysql вместо Oracle, потвърждава този факт:
import static org.junit.Assert.assertEquals;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
public class DBTest {
public Connection openConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
c.setAutoCommit(false);
return c;
}
@Test
public void testSO25886466() throws SQLException, ClassNotFoundException {
{
Connection c = openConnection();
PreparedStatement delete = c.prepareStatement("delete from temp");
delete.executeUpdate();
c.commit();
c.close();
}
{
Connection c = openConnection();
PreparedStatement insert = c.prepareStatement("insert into temp values ('a', 'b')");
insert.execute();
//c.commit(); as the op says, DONT commit!!
c.close(); //WITHOUT having closed the statement or committing the transaction!!
}
{
Connection c = openConnection();
PreparedStatement select = c.prepareStatement("select count(*) from temp");
select.execute();
ResultSet rs = select.getResultSet();
while(rs.next()){
assertEquals(0/*i'd expect zero here!*/, rs.getInt(1));
}
rs.close();
select.close();
c.close();
}
}
}
Според http://tomcat.apache.org/tomcat-7.0 -doc/jdbc-pool.html :
Бих препоръчал да не задавате removeAbandoned
така че Oracle затваря връзката след изчакване от страна на сървъра, вместо Tomcat да я затваря. Oracle вероятно няма да ангажира транзакцията в този случай, но ще трябва да тествате това.
Като алтернатива, можете ли да увеличите removeAbandonedTimeout
настройка, така че вашата програма да може да завърши и никакви връзки да не бъдат изоставени?
Друг проблем, който имате, е, че вашето приложение е обвързано с Oracle, защото разчитате на внедряването на драйвера, където спецификацията има дупка в нея. Ако можете, програмирайте спрямо спецификациите, така че да можете свободно да мигрирате приложението си към друга база данни, въпреки че знам, че това е трудно на практика.
Напълно различно решение би било да се вземе пул от връзки с отворен код и да се разшири с AOP прихващач, който може да прихваща повиквания към close
и разберете дали транзакцията е била ангажирана и ако не, извикайте rollback
на връзката. Това обаче е доста сложно решение... :-)