Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Tomcat-jdbc-Verbindungspool – Zurücksetzen abgebrochener Transaktionen

Laut http://docs .oracle.com/javase/7/docs/api/java/sql/Connection.html#close() :

Dieser Test, bei dem Mysql statt Oracle verwendet wird, bestätigt diese Tatsache:

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();
        }
    }
}

Gemäß http://tomcat.apache.org/tomcat-7.0 -doc/jdbc-pool.html :

Ich würde empfehlen, removeAbandoned nicht zu setzen sodass Oracle die Verbindung nach einem Timeout auf der Serverseite schließt, anstatt dass Tomcat sie schließt. Oracle wird die Transaktion in diesem Fall wahrscheinlich nicht festschreiben, aber Sie müssten dies testen.

Alternativ könnten Sie removeAbandonedTimeout erhöhen einstellen, damit Ihr Programm beendet werden kann und keine Verbindungen abgebrochen werden?

Ein weiteres Problem besteht darin, dass Ihre Anwendung an Oracle gebunden ist, weil Sie sich auf die Treiberimplementierung verlassen, bei der die Spezifikation eine Lücke aufweist. Wenn Sie können, programmieren Sie gemäß den Spezifikationen, sodass Sie Ihre Anwendung frei auf eine andere Datenbank migrieren können, obwohl ich weiß, dass dies in der Praxis schwierig ist.

Eine völlig andere Lösung wäre, einen Open-Source-Verbindungspool zu nehmen und ihn mit einem AOP-Interceptor zu erweitern, der Aufrufe zum close abfangen kann und ermitteln Sie, ob die Transaktion festgeschrieben wurde, und rufen Sie andernfalls rollback auf auf der Verbindung. Das ist allerdings eine ziemlich komplexe Lösung... :-)