Предыстория : я работаю на 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 просто нужно будет ввести на панели схемы (слева). Я надеюсь, что это не сломает слишком много старых скрипок, но я думаю, что это просто то, что нужно сделать для обеспечения согласованности данных. Благодарность!