Отключить явные коммиты в JDBC, обнаружить их в SQL или перевести базу данных в состояние только для чтения

12

Предыстория : я работаю на http://sqlfiddle.com (мой сайт), и пытаюсь предотвратить один из возможных способов злоупотребления там. Я надеюсь, что, задавая вопрос о проблеме, которую я сейчас решаю, я случайно не усугублю потенциальное злоупотребление, но что вы можете сделать? Я верю вам, ребята.

Я хотел бы запретить любому пользователю выполнять явные вызовы 'commit' в данном блоке транзакции. Из контекста SQL Fiddle блок транзакции - это код, который выполняется на правой панели. По сути, я зацикливаюсь и выполняю список текстовых SQL-команд и хочу убедиться, что все сделанные ими изменения будут отменены в конце пакета. Обычно их изменения откатываются, но иногда в тексте есть явное выражение 'commit', и, конечно, мой откат не сработает. Эта явная фиксация весьма вероятна для пользователя, пытающегося нарушить схему в SQL Fiddle, поэтому другие люди, работающие над ней, увидят ошибки.

Основной желаемый результат : Я хотел бы отключить явные коммиты на уровне JDBC, если это возможно. Это связано с тем, что мне приходится поддерживать несколько поставщиков баз данных, и, конечно, у каждого есть свои причуды на низком уровне.

Резервный вариант : если невозможно настроить JDBC на отключение явных фиксаций, тогда я буду открыт для решений по обнаружению явных фиксаций при обработке пакета для каждого из следующих серверных компонентов: SQL Server, Oracle, MySQL и PostgreSQL.

Для SQL Server я подумал об этом решении: проанализируйте план запроса XML для оператора перед его выполнением и проверьте наличие записи, соответствующей этому XPath:

//*[@StatementType="COMMIT TRANSACTION"]

Я думаю, что это будет работать очень хорошо для SQL Server. Однако этот подход не работает для других типов БД. Вывод плана выполнения XML Oracle для явных фиксаций не ссылается на тот факт, что вы выполняете инструкцию commit (а просто повторяет вывод плана исполнения из запросов, которые он фиксирует). PostgreSQL и MySQL вообще не предоставляют никакого вывода плана выполнения (XML или иным образом) для явных фиксаций.

Это оставляет меня с проверкой фактического утверждения для слова «совершать». Это будет работать, за исключением того, что возможны все возможные варианты:

declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);

Выше приведен пример для SQL Server (который я мог бы обойти), но я бы предположил, что аналогичные вещи будут возможны для Oracle, MySQL и PostgreSQL. Я ошибаюсь в этом предположении? Может быть, они не позволят «динамические» операторы коммита? Не стесняйтесь использовать SQL Fiddle (желательно не примерную схему или чью-то другую, над которой, вероятно, будут работать), чтобы посмотреть, сможете ли вы сделать что-то подобное в Oracle, MySQL и PostgreSQL. Если нет, возможно, простое обнаружение строк может работать для них.

Еще одна возможность

Мне пришёл в голову другой вариант - если вы знаете способ установить любую из этих баз данных в режиме только для чтения, например, в этом режиме ничего не может быть зафиксировано, это тоже может сработать. Мне нужно было бы разрешить запуск транзакций и запуск кода внутри них, лишь бы ничто не могло быть зафиксировано в этом режиме. Это возможно?

Обновить

То, что я недавно узнал - это на самом деле не проблема PostgreSQL. Очевидно, что коммиты, выпущенные в блоке транзакции, не будут применяться, если этот же блок в конечном итоге получит откат (в Postgres). Итак, Ура для Postgres!

Благодаря ссылке Фила на пост SO, я думаю, что могу использовать взлом DEFERRABLE INITIALLY DEFERRED для Oracle, чтобы выполнить то, что мне нужно (ошибка будет выдана, если будет выдан коммит, но я могу обойти это). Это должно обратиться к Oracle. (Я на мгновение подумал, что здесь могут работать вложенные транзакции, но похоже, что Oracle не поддерживает вложенные транзакции? Во всяком случае, я не смог найти ничего, что работало бы таким образом).

На самом деле пока нет решения для MySQL. Пробовал использовать вложенные транзакции, но это не работает. Я серьезно думаю о более радикальных подходах к MySQL, таких как запрет на использование чего-либо, кроме SELECT, на правой стороне или удаление / воссоздание БД после каждого запроса. Ни один не звучит хорошо, хотя.

разрешение

Итак, я реализовал описанные решения для SQL Server и Oracle, и, как я уже говорил, это на самом деле не проблема для PostgreSQL. Для MySQL я сделал несколько неудачный шаг, ограничив панель запросов только для выбора операторов. DDL и DML для MySQL просто нужно будет ввести на панели схемы (слева). Я надеюсь, что это не сломает слишком много старых скрипок, но я думаю, что это просто то, что нужно сделать для обеспечения согласованности данных. Благодарность!

Джейк Физель
источник
Стоит упомянуть - я также провел много исследований по поиску триггеров «предмит». Похоже, что таких не существует, поэтому, к сожалению, это тоже не вариант.
Джейк Физель
2
Для Oracle это выглядит как хороший хитрый способ перехвата COMMIT: stackoverflow.com/a/6463800/790702 Что он не упоминает, так это то, что вы должны быть в состоянии поймать нарушение ограничений и в своем коде, чтобы остановить 2-ю ситуацию происходит.
Philᵀᴹ
@ Единственная проблема в том, что я не могу (и не хочу) контролировать определение каждой из таблиц (они определены на левой панели). Чтобы не было предложения DEFERRABLE INITIALLY DEFERRED (если только не существует какого-либо способа сделать это автоматически для всех таблиц - скажем, с помощью системного триггера, отвечающего на создание операторов таблицы? Тьфу)
Джейк Физель
1
@NickChammas Мне нужно отключить фиксации, чтобы я мог держать схему (как определено на левой боковой панели) в фиксированном состоянии. Может быть любое количество людей, пишущих запросы к одной и той же схеме, которые пытаются решить одну и ту же проблему. Чтобы они не мешали друг другу, я должен быть уверен, что структура и данные не изменятся. Это достигается с помощью отката транзакций, но это не произойдет, если правый код будет зафиксирован.
Джейк Физель
2
@RickJames DDL создает неявные коммиты в MySQL и Oracle, но не в PostgreSQL или SQL Server. Механизмы, которые я реализовал после этого поста, касаются этой проблемы. Что касается ввода произвольного SQL - вот и весь смысл!
Джейк Физель

Ответы:

3

Для Oracle это выглядит как хороший хитрый способ перехвата COMMIT:

/programming//a/6463800/790702

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

Philᵀᴹ
источник
Отлично, еще раз спасибо, Фил. Я смог эффективно использовать эту технику для Oracle. Это заставляет меня желать, чтобы другие базы данных поддерживали отложенные ограничения.
Джейк Физель
Не стоит беспокоиться. Заходите в чат и говорите привет :)
Philᵀᴹ