Динамические уровни изоляции транзакции для @Transactional - PullRequest
0 голосов
/ 04 октября 2018

Я работал над исправлением 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?

1 Ответ

0 голосов
/ 05 октября 2018

Я сомневаюсь в предположении, что динамические уровни изоляции являются обязательным требованием.Когда уровни изоляции имеют значение, проблема заключается не в каких-то конкретных данных, а в способе объединения самих операторов.Представляется маловероятным, что у вас будет случай, когда метод, вызываемый с одним набором данных, должен иметь один уровень изоляции, в то время как тот же метод, вызываемый с другим набором данных, должен проходить под другим уровнем изоляции.

Я предполагаю, что основная проблема с унаследованным кодом заключается в том, что нет концепции транзакционного уровня обслуживания.Вместо этого у вас есть мешанина объектов доступа к данным, которые вызываются непосредственно контроллерами, и уровни изоляции, по-видимому, определяются случайно.

Задание деталей транзакции, таких как уровень изоляции, необходимо выполнять на уровне обслуживания.Я хотел бы пройтись по контроллерам, отделить вещи, которые они делают на веб-уровне, от бизнес-логики и перенести бизнес-логику в методы обслуживания, которые можно комментировать такими вещами, как уровень изоляции.

Как только вы это сделаете, у вас будут DAO, которые можно повторно использовать в разных сервисах, где уровень изоляции задан в конкретной службе, и все соединения для выборки кода, перехвата исключений и закрытия ресурсов jdbc могут быть удалены,

...