Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Pool de conexões jdbc do Tomcat - reversão de transação abandonada


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

Este teste, usando o Mysql em vez do Oracle, confirma este fato:
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();
        }
    }
}

De acordo com http://tomcat.apache.org/tomcat-7.0 -doc/jdbc-pool.html :

Eu recomendaria não configurar removeAbandoned para que o Oracle feche a conexão após um tempo limite no lado do servidor, em vez de o Tomcat fechá-la. A Oracle provavelmente não confirmará a transação nesse caso, mas você precisaria testar isso.

Como alternativa, você pode aumentar o removeAbandonedTimeout configuração, para que seu programa possa terminar e nenhuma conexão seja abandonada?

Outro problema que você tem é que seu aplicativo ficou vinculado ao Oracle porque você está confiando na implementação do driver onde a especificação tem um furo. Se você puder, programe de acordo com as especificações, para que você fique livre para migrar seu aplicativo para um banco de dados diferente, embora eu saiba que isso é difícil na prática.

Uma solução completamente diferente seria pegar um pool de conexão de código aberto e estendê-lo com um interceptador AOP que pode interceptar chamadas para close e descubra se a transação foi confirmada e, caso contrário, chame rollback na conexão. Essa é uma solução bastante complexa... :-)