【问题标题】:ORA-14552: cannot perform a DDL, commit or rollback inside a query or DMLORA-14552: 无法在查询或 DML 中执行 DDL、提交或回滚
【发布时间】:2013-05-10 17:03:14
【问题描述】:

我们在 Oracle WebLogic Servers 中部署了一些 Web 服务,这些服务的主要职责是调用存储过程并将这些数据发送给客户端。服务的技术栈是:

  • JAX-WS
  • Spring 框架
  • MyBatis

服务从 WebLogic 提供的连接池获取到数据库的连接。几个月来,服务运行良好,但今天我们遇到了以下问题:

SERVER: WLSDesa_ManagedServer1 [DEBUG] [15-05-2013 12:23:03.897] (JakartaCommonsLoggingImpl.java:46) - ooo Using Connection [weblogic.jdbc.wrapper.PoolConnection_oracle_jdbc_driver_T4CConnection@59bd]
SERVER: WLSDesa_ManagedServer1 [DEBUG] [15-05-2013 12:23:03.898] (JakartaCommonsLoggingImpl.java:46) - ==>  Preparing: { call package.iOnlyDoASelect( ?, ?) } 
a.package.from.project.CommonException: org.springframework.jdbc.UncategorizedSQLException: 
### Error querying database.  Cause: java.sql.SQLException: ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML 

### The error may exist in a/package/from/the/project/ImAMyBatisMap.xml
### The error may involve a.package.from.the.project.ImADaoClass.invokeProcedure-Inline
### The error occurred while setting parameters
### SQL: { call package.iOnlyDoASelect(   ?,   ?)   }
### Cause: java.sql.SQLException: ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML 

; uncategorized SQLException for SQL []; SQL state [72000]; error code [14552]; ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML 
; nested exception is java.sql.SQLException: ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML 

该过程只是一个Select对几个表,我们可以从另一个Java应用程序和数据库客户端正常调用它;在服务中,我们没有使用任何显式的事务管理代码。该问题偶尔发生并使服务无用。我们的解决方法是重新启动 WebLogic Server 或关闭自动提交,然后再打开。这种情况几乎每天发生 5 次。

有什么线索吗? WebLogic 是否相关,是数据库问题还是它的 Web 服务代码?

【问题讨论】:

  • 为什么要使用自动提交?通常不是使用数据库的最佳方式。 (审计/日志记录之类的事情是否发生在您使用的过程/功能中?)
  • 包内的select 是否调用了任何函数,这些函数可能已经用编译指示声明为安全但实际上正在做他们不应该做的事情?从您所说的听起来不太可能,但如果呼叫在where 子句中并且并不总是到达,则可能是间歇性的。也不要认为它完全匹配,但是当它发生时,您是否从池中获得了新创建的连接,并且您是否有提交的登录触发器? (显然是抓着稻草……)
  • @ik_zelf 我们使用 WebSphere 附带的连接池的默认配置。我们一直在尝试使用自动提交来解决此问题。
  • @AlexPoole 如何识别一个用 pragma 声明为安全的函数?
  • 实际上我不确定它是否需要编译指示。您可以拥有一个只执行 commit 的函数,并将其包含在查询中,只要它永远不会被评估;如果确实如此,您将收到此错误。 (所以它取决于谓词评估的顺序和结果)。您可以搜索所有源代码以查找提交/回滚/等。但是您不知道调用的是什么,因此您可能需要从另一端开始并查看您的查询正在调用哪些函数,并查看它们正在调用什么等。您可以将其缩小到并非总是如此调用,或尝试单独调用它们。

标签: web-services oracle jakarta-ee transactions weblogic


【解决方案1】:

根据评论,这不是答案,而是显示可能发生的情况的示例,如果您的查询在某个时候调用了一个函数。

create function f42 return number as
begin
    commit;
    return 0;
end;
/

Function created.

SQL> select * from dual where extract(day from sysdate) = 16 or f42 = 0;

D
-
X

这很好,因为今天是16号,所以or的第一部分为真,第二部分不需要评估;所以这个函数没有被调用。 改变我正在寻找的那一天:

SQL> select * from dual where extract(day from sysdate) = 15 or f42 = 0;

select * from dual where extract(day from sysdate) = 15 or f42 = 0
                                                           *
ERROR at line 1:
ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML
ORA-06512: at "STACKOVERFLOW.F42", line 3

这次or的第一部分是假的,所以它确实调用了函数,这会引发错误。

但错误堆栈会向您显示问题的真正来源,除非您当然正在捕获(并压缩)堆栈,或者您的客户没有报告它。从 SQL*Plus 直接调用包过程将显示整个堆栈 - 假设您知道导致问题的参数并且您没有压缩错误。

但尚不清楚该问题是否仅影响某些参数值,还是基于某些暂时的(例如sysdate),或者确实是完全由其他原因引起的。我会先看看您是否可以像这样可靠地复制它,如果可以,那么错误堆栈应该让您更好地了解正在发生的事情。

【讨论】:

  • 该过程只是一个普通的 Select,我们不会调用任何涉及事务的过程。也许我们应该注意触发因素?
  • @CarlosGavidia - 您可以检查登录触发器,但不确定是否有其他类型的触发器。我不想鞭打一匹死马,但我想到选择可能位于调用函数的视图上,这不太明显。您能否通过普通客户端而不是 Java(即 SQL*Plus 或 SQL Developer 或类似)实现它?
  • 取消更新:一个错误发生,还有其他程序抛出同样的异常
  • @CarlosGavidia - 好的,所以这几乎排除了 *8-) 登录触发器是我目前最好的猜测(这可能意味着连接被占用的潜在问题,导致池不得不扩大),但根本不相信。
  • +1 我认为这里最重要的想法是找到错误的行号。无需猜测错误发生在哪里,Oracle 会告诉你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
相关资源
最近更新 更多