Я работал над исправлением SQL-инъекций в очень старой базе кода Java + Spring MVC с несколькими сотнями классов на уровне DAO, который в настоящее время использует java.sql.PreparedStatement
& java.sql.Connection
.
Изоляция соединения с БДуровень, фиксация соединения с БД и откат соединения напрямую обрабатываются на объекте Connection
с использованием - Connection.setIsolationLevel(int isolationLevel)
, Connection.commit()
& Connection.rollback()
.
Допустим, у меня есть метод, подобный приведенному ниже,
public List<String> getReportName() {
try {
Connection connection = getConnection();
connection.setIsolationLevel(Isolation.READ_UNCOMMITTED); // Just an example
String sql = //ActualSQLString;
PreparedStatement pstmt = connection.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
......
......
}
} catch (Exception e) {
...
} finally {
//Close connection, statement & result set
}
}
, если я хочу ввести org.springframework.jdbc.core.JdbcTemplate
вместо java.sql.PreparedStatement
, существует автоматическое требование, от которого я избавляюсьвызов connection.setTransactionIsolation(isolationLevel)
, принятие и откат, поскольку JdbcTemplate работает на DatSource вместо отдельного объекта соединения.Поэтому я изменяю выше метод, как показано ниже.getJdbcTemplate()
только для иллюстрации, и я могу получить это через @Autowired
.Кроме того, это требование не имеет ничего общего с основным требованием исправления SQL-инъекций.
@Transactional(isolation = Isolation.READ_UNCOMMITTED, readOnly = true)
public List<String> getReportName() {
try {
String sql = //ActualSQLString;
return getJdbcTemplate().queryForList(sql);
} catch (Exception e) {
...
}
}
Сценарий коммита и отката обрабатывается атрибутом rollbackFor
, если бы это происходило в вышеуказанном методе.
Теперь меня смущает, когда сигнатура метода выглядит следующим образом: соединение создается в другом методе класса DAO, уровень изоляции устанавливается там и передается этому методу (который находится в другом классе DAO),
public List<String> getReportName(Connection connection) {
try {
String sql = //ActualSQLString;
PreparedStatement pstmt = connection.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
......
......
}
} catch (Exception e) {
...
} finally {
//Close connection, statement & result set
}
}
Существуют различные вызывающие стороны этого метода из разных классов, и иерархия вызовов обычно состоит из нескольких уровней, т.е. объект подключения был создан на два или три уровня выше, и изоляция установлена там.
Например, соединение создается в DAOClass1.method () и передается вышеупомянутому getReportName DAOClass3.
DAOClass1.method () -> DAOClass2.method (Соединение с подключением) -> DAOClass3.getReportName (Соединение с подключением)
Возможен ли этот сценарий для реинжиниринга путем введения @Transactional
& JdbcTemplate
комбо?Буду ли я применять @Transactional
только в инициаторе вызова, где создается Connection
, или в этом методе тоже?
Полагаю, это скорее случай распространения транзакции, но немного запутанный.
Мой вопрос дублирует приведенный ниже Вопрос № 1, но мне нужно решение для моего конкретного сценария.
Смежный вопрос 1 - Переменные уровни изоляции транзакций по запросу
Смежный вопрос 2 - Как получить пружинный шаблон JdbcTemplate для read_uncommitted?