背景:我正在http://sqlfiddle.com(我的网站)上工作,并试图防止可能的一种滥用途径。我希望通过询问我当前要解决的问题,我不会无意间使潜在的虐待更为严重,但是您能做什么?我相信你们。
我想防止任何用户在给定的交易块内发出明确的“提交”调用。从SQL Fiddle的上下文来看,事务块是在右侧面板上执行的代码。基本上,我遍历并执行一系列明文SQL命令,并且我想确保它们所做的所有更改都将在批处理结束时回滚。通常,它们的更改会回滚,但是有时文本中会包含明确的“ commit”语句,因此我的回滚当然是行不通的。用户试图破坏SQL Fiddle上的架构时,很可能发生这种显式提交,因此其他从事此操作的人将看到错误。
主要期望结果:如果可能,我想在JDBC级别禁用显式提交。这是因为我必须支持多个数据库后端供应商,并且当然每个供应商都有其低级的怪癖。
Fallback选项:如果无法将JDBC配置为禁用显式提交,那么我将接受在处理以下每个后端批处理时检测显式提交的解决方案:SQL Server,Oracle,MySQL和PostgreSQL。
对于SQL Server,我想到了这种解决方案:在执行该语句之前,先解析XML查询计划中的语句,然后检查是否存在与该XPath相匹配的条目:
//*[@StatementType="COMMIT TRANSACTION"]
我认为这对于SQL Server来说会很好。但是,这种方法不适用于其他数据库类型。Oracle针对显式提交的XML执行计划输出未引用您正在运行commit语句的事实(而只是重复从其提交的查询中重复执行计划输出)。PostgreSQL和MySQL根本不为显式提交提供任何执行计划输出(XML或其他方式)。
剩下的工作就是检查“ commit”一词的实际陈述。这将起作用,除非可能存在各种变化:
declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);
上面是SQL Server的示例(我可以解决),但是我想Oracle,MySQL和PostgreSQL可能会发生类似的事情。我在这个假设上错了吗?也许他们不允许“动态”提交语句?随意使用SQL Fiddle(最好不要使用示例架构或可能正在使用的其他示例)来查看是否可以在Oracle,MySQL和PostgreSQL中进行类似的操作。如果没有,也许简单的字符串检测可能适用于那些。
还有另一种可能性
我想到了另一个选择-如果您知道一种将这些数据库中的任何一个设置为只读模式的方法,例如在该模式下,什么也不能提交,那也可以工作。只要在该模式下什么也不能提交,我就仍然需要允许启动事务并在其中运行代码。那可能吗?
更新资料
我最近学到的-PostgreSQL实际上不是问题。显然,如果同一交易块最终被回滚(在Postgres中),则该交易块中发出的提交将不适用。所以为Postgres致敬!
多亏了Phil在SO帖子上的链接,我想我可以使用DEFERRABLE INITIALIALLY DEFERRED hack for Oracle来完成我要执行的操作(如果发出了提交,将会引发错误,但是我可以解决这个问题)。这应该针对Oracle。(我想了一会儿嵌套事务可能在这里工作,但是Oracle似乎不支持嵌套事务?无论如何,我找不到以这种方式工作的任何东西)。
真的还没有针对MySQL的解决方案。使用嵌套事务进行了尝试,但这似乎不起作用。我正在认真考虑MySQL的更严格的方法,例如不允许在右侧使用SELECT或在每次查询后删除/重新创建数据库。听起来都不好。
解析度
因此,我现在已经为SQL Server和Oracle实现了所描述的解决方案,并且正如我提到的那样,对于PostgreSQL来说这实际上不是问题。对于MySQL,我采取了一些不幸的步骤,将查询面板限制为仅选择语句。仅需在架构面板(左侧)上输入用于MySQL的DDL和DML。我希望这不会破坏太多的旧提琴,但是我认为这只是确保数据一致性所要做的。谢谢!