blob: 3ab4fd7ef473043140871af905efd0ea6f647681 [file] [log] [blame]
/*
* Copyright (c) 2010, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2015 Dies Koper (Fujitsu) All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Created Jan 10, 2010 - Dies Koper (Fujitsu), patterned after SybaseTransactionIsolationListener
// bug 288715: Tests: Several Core LRG tests hang on Symfoware.
package org.eclipse.persistence.testing.framework;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor;
import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform;
import org.eclipse.persistence.sessions.SessionEvent;
import org.eclipse.persistence.sessions.SessionEventAdapter;
/*
* <p>Apache Derby and Symfoware in general are configured to use transaction isolation level
* READ_COMMITTED or SERIALIZABLE.</p>
* That causes a few tests to hang, or fail with an error message saying that the table is locked
* (depending on a setting on the database side): these tests begin transaction, update a row,
* then (before the transaction has been committed) attempt to read the row through another connection.
*
* To allow these reads to go through (and read the uncommitted data) connection isolation level
* should be temporary switched to READ_UNCOMMITTED.
*
* This class switches the acquired connection to READ_UNCOMMITTED and then sets back the original
* isolation level before connection is released.
*
* Note that for the above scenario only read connections require level READ_UNCOMMITTED.
*
* @author Dies Koper
*/
public class TransactionIsolationLevelSwitchListener extends SessionEventAdapter {
private final String statement;
Map<Connection, String> connections = new HashMap<Connection, String>();
public TransactionIsolationLevelSwitchListener(DatabasePlatform platform) {
if (platform.isDerby()) {
statement = "set isolation ";
} else if (platform.isMaxDB()) {
statement = "set transaction isolation level ";
} else {
statement = "";
}
}
@Override
public void postAcquireConnection(SessionEvent event) {
Connection conn = ((DatabaseAccessor) event.getResult())
.getConnection();
Statement stmt1 = null;
String isolationLevel = "";
try {
int i = conn.getTransactionIsolation();
switch (i) {
case 1:
isolationLevel = "READ UNCOMMITTED";
break;
case 2:
isolationLevel = "READ COMMITTED";
break;
case 4:
isolationLevel = "REPEATABLE READ";
break;
case 8:
isolationLevel = "SERIALIZABLE";
break;
}
if (i > 0) {
// If conn1 began transaction and updated the row (but hasn't
// committed the transaction yet),
// then conn2 should be able to read the original (not updated)
// state of the row.
// Without this conn2 reading the row hangs on Symfoware.
stmt1 = conn.createStatement();
stmt1.execute(statement + "READ UNCOMMITTED");
connections.put(conn, isolationLevel);
}
} catch (SQLException sqlException) {
throw new TestProblemException("postAcquireConnection failed. ",
sqlException);
} finally {
if (stmt1 != null) {
try {
stmt1.close();
} catch (SQLException ex) {
// Ignore
}
}
}
}
@Override
public void preReleaseConnection(SessionEvent event) {
Connection conn = ((DatabaseAccessor) event.getResult())
.getConnection();
Statement stmt = null;
try {
String isolationLevel = connections.remove(conn);
if (isolationLevel != null) {
// reset the original transaction isolation.
stmt = conn.createStatement();
stmt.execute(statement + isolationLevel);
stmt.close();
}
} catch (SQLException sqlException) {
throw new TestProblemException("preReleaseConnection failed. ",
sqlException);
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException ex) {
// Ignore
}
}
}
}
}