在JDBC中禁用显式提交,在SQL中检测它们,或将数据库置于只读状态


12

背景:我正在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。我希望这不会破坏太多的旧提琴,但是我认为这只是确保数据一致性所要做的。谢谢!


值得一提的是-我也做了很多研究以研究“预提交”触发器。似乎这些都不存在,所以不幸的是这也不是一个选择。
杰克·菲塞尔

2
对于Oracle,这似乎是捕获COMMIT的好方法:stackoverflow.com/a/6463800/790702他没有提到的是,您也应该能够在代码中捕获约束违例,从而停止第二种情况。发生。
Philᵀᴹ

@Phil唯一的问题是我没有(也不真正想要)控制每个表的定义(这些表在左面板上定义)。这样就不会存在DEFERRABLE INITIALLY DEFERRED子句(除非有某种方法可以对所有表自动执行此操作-例如通过响应创建表语句的系统触发器来进行此操作?)
Jake Feasel 2012年

1
@NickChammas我需要禁用提交,以便可以将架构(由左侧面板定义)保持在固定状态。可能有许多人针对同一模式编写查询以尝试解决同一问题。为了防止它们相互干扰,我需要确保保持结构和数据不变。这是通过回滚事务来完成的,但是如果提交了右侧代码,则不会发生这种情况。
杰克·菲塞尔

2
@RickJames DDL在MySQL和Oracle中创建隐式提交,但不在PostgreSQL或SQL Server中创建隐式提交。我在这篇文章之后实现的机制可以解决这个问题。至于输入任意SQL,这就是重点!
杰克·菲塞尔

Answers:


3

对于Oracle,这似乎是捕获COMMIT的好方法:

/programming//a/6463800/790702

他没有提到的是,您也应该能够在代码中捕获约束违例,以阻止第二种情况的发生。


太好了,再次感谢Phil。我已经能够很好地利用Oracle的这项技术。我希望其他数据库支持延迟约束。
杰克·菲塞尔

别担心。拖放到聊天打招呼:)
Philᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.