Alla som jobbar med serverapplikationer i Java har väl någon gång stött på behovet av en connection pool. Länge var Apache DBCP den dominerande poolen, eventuellt med c3p0 som alternativ. Båda dessa har sina egna mer eller mindre obskyra problem.

För en del år sedan dök det så upp en ny pool, som helt enkelt heter JDBC Connection Pool. Den ingår numera som en modul i Tomcat, är betydligt modernare än sin föregångare och den skall fungera med alla containrar (Tomcat, Jetty, JBoss etc). Den har dessutom en hel uppsjö inställningar, skall fungera bättre på multi-core-maskiner och är enklare i sin interna uppbyggnad än DBCP. Så här ser Maven-beroendet ut just nu:

<dependency>
    <groupId>org.apache.tomcat</groupId> 
    <artifactId>tomcat-jdbc</artifactId> 
    <version>7.0.26</version>
</dependency>

Ett vanligt problem med databaskopplingar är connections som ”dör” på olika sätt. Routrar och brandväggar konfigureras ibland så att kopplingar bara får ha en viss livslängd, och samma sak gäller databasservrar – och så har vi ju ibland helt vanliga nätverksproblem också. Det traditionella sättet att lösa det på är att använda en så kallad ”validation query”. Det innebär att connection-poolen, t.ex. innan den delar ut en connection från poolen, skickar en testfråga till databasen, t.ex. SELECT 1. Exakt vilken fråga som är lämplig beror på vilken databas det är, och t.ex. MySQL har en speciell fråga avsedd för detta ändamål.

Min erfarenhet är att detta inte alltid funkar något vidare. Beroende på vilket tillstånd TCP-kopplingen har så kan en sådan fråga hänga sig en lång stund, vilket leder till att poolen svälter. Det man normalt vill uppnå är att poolen bara kastar connections som inte svarar snabbt, och skapar nya i stället. JDBC Connection Pool tillsammans med Java 1.6 har en trevlig lösning på det, och nu börjar vi äntligen närma oss min poäng!

Sedan Java 1.6 finns en metod i java.sql.Connection som heter isValid. Denna låter JDBC-drivern självt avgöra om en koppling kommer att fungera, i stället för att använda mystiska validation queries. Metoden tar som parameter en timeout i sekunder som är separat från övriga timeouts. Detta passar som handen i handsken med en inställning i JDBC Connection Pool som heter validatorClassName. Man sätter validatorClassName till namnet på en klass som man själv implementerar, och poolen anropar den för att kontrollera om en connection får användas, innan den ger ut den till klientkoden. Så här ser min variant på validator-klass ut:


public class JDBCValidator implements Validator { 
    private static final Logger LOGGER = 
        LoggerFactory.getLogger(JDBCValidator.class); 

    @Override
    public boolean validate(Connection connection, int validateAction) {
        LOGGER.trace("validate called for connection {}, validateAction = {}", connection, validateAction); 

        try { 
            // 10 seconds should do it 
            if (connection.isValid(10)) { 
                LOGGER.trace("Connection {} is VALID", connection); 
                return true; 
            } 

            LOGGER.warn("Invalid DB connection detected"); 
            return false; 
        } catch (SQLException e) { 
            LOGGER.warn("Invalid DB connection detected", e); 
            return false;
        }
    } 
}

Tack vare loggningen så får man stenkoll på hur databasen och nätet verkar agera, och det funkar dessutom varje gång!