当前位置: 首页 > 面试题库 >

在当前事务之外提交事务(例如Oracle中的自主事务)

澹台华采
2023-03-14
问题内容

我需要从存储过程中写入日志表。现在,此日志信息必须能够在回滚过程中幸免。

我知道以前曾问过这个问题,但是我的情况有所不同,在这些问题中找不到我的问题的答案。

当存储过程中没有错误时,事情就很简单了,日志表中的条目就在那里。
当有错误时,事情就变得复杂了。
在该过程中,我可以在catch中进行回滚,然后将数据插入日志表,我知道并且我已经在这样做了。
但是问题是当存储过程这样调用时:

begin transaction
exec myStoredProcedure
rollback transaction
select * from myLogTable

我知道这段代码没有多大意义,我尽量减少代码来演示我的问题。
如果存储过程的调用者执行了提交/回滚,那么我在存储过程中所做的操作就无关紧要。我的登录信息将始终回滚。

我也不能使用临时表技巧,该技巧是返回我要记录的数据,并让调用者在完成回滚后使用该数据将其插入到日志表中,因为调用者是我不希望使用的外部应用程序有来源。

日志记录是在一个单独的过程中完成的,该过程只有一行代码,即插入到日志表中。
我需要的是一种在当前事务之外的此过程中提交插入的方法,以便它在任何回滚后都可以幸免。

有没有办法做到这一点 ?

解决方案:

我使用了lad2025答案,到目前为止,它没有任何问题或性能问题。
但是这个程序每天只会被调用大约1000次,所以这并不是很多,所以我想我也不必指望任何问题。


问题答案:

这是一个非常有趣的话题,因此让我们检查一下MS如何处理它。

第一份文档:将Oracle迁移到SQL Server-2014-和-Azure-SQL-
DB.pdf

第152页。

模拟Oracle自主事务

本部分描述了SSMA for Oracle V6.0如何处理自主事务(PRAGMA
AUTONOMOUS_TRANSACTION)。这些自主事务在Microsoft SQL Server 2014中没有直接等效项。

当您将PL /
SQL块(匿名块,过程,函数,打包过程,打包函数,数据库触发器)定义为自主事务时,会将该块中的DML与调用者的事务上下文隔离。该块成为由另一个事务(称为主事务)启动的独立事务。

要将PL / SQL块标记为自主事务,只需在声明部分中包含以下语句:PRAGMA AUTONOMOUS_TRANSACTION;

SQL Server 2014不支持自主事务。 将Transact-SQL块与事务上下文隔离的唯一方法是打开新连接。

使用 xp_ora2ms_exec2 扩展过程及其与SSMA 6.0 Extension Pack捆绑在一起的扩展版本
xp_ora2ms_exec2_ex
打开新事务。该过程的目的是在新连接中调用任何存储过程,并帮助在函数体内调用存储过程。xp_ora2ms_exec2过程具有以下语法:

xp_ora2ms_exec2
<active_spid> int,
<login_time> datetime,
<ms_db_name> varchar,
<ms_schema_name> varchar,
<ms_procedure_name> varchar,
<bind_to_transaction_flag> varchar,
[optional_parameters_for_procedure];

然后,您需要在服务器上安装存储过程和其他脚本: 适用于Oracle Extension
Pack的SSMA(仅适用于Oracle Extension
Pack.7.5.0.msi的SSMA)。

您的存储过程将变为:

CREATE TABLE myLogTable(i INT IDENTITY(1,1),
                        d DATETIME DEFAULT GETDATE(),
                        t NVARCHAR(1000));
GO

CREATE OR ALTER PROCEDURE my_logging
   @t NVARCHAR(MAX)
AS
BEGIN
   INSERT INTO myLogTable(t) VALUES (@t);
END;
GO

CREATE OR ALTER PROCEDURE myStoredProcedure
AS
BEGIN
    -- some work
    SELECT 1;
    INSERT INTO myLogTable(t) 
    VALUES ('Standard logging that will perish after rollback');

    DECLARE @login_time DATETIME = GETDATE();
    DECLARE @custom_text_to_log NVARCHAR(100);
    SET @custom_text_to_log=N'some custom loging that should survive rollback';
    DECLARE @database_name SYSNAME = DB_NAME();

    EXEC master.dbo.xp_ora2ms_exec2_ex 
       @@spid,
       @login_time,
       @database_name,
       'dbo',
       'my_logging',
       'N',
       @custom_text_to_log;
END;

最后的电话:

begin transaction
exec myStoredProcedure
rollback transaction
select * from myLogTable;

输出:

i   d          t
2   2017-08-21 some custom loging that should survive rollback


 类似资料:
  • 我的路线如下 我知道(A)处的JMS消费者将在每次轮询时分叉JMS事务,并附加到线程。(B)中的事务处理节点也将在交换到达那里并连接到线程后分叉JPA事务。 请在下面找到我的问题: > < li >能否将两个不同的事务附加到一个线程上(如上所示)? < li >如果是,哪一个应该被停职? < li> 上述路由的提交和回滚顺序应该是什么? 注:我没有从骆驼在行动第二版中找到任何明显的答案,所以请指导

  • 您能否帮助解决Resin+Oracle上XA事务的问题: 我们有WebApp,它必须执行涉及Oracle11.2.0.1和EHCache2.7的业务事务。(实际上可能有各种组合--两个不同的Oracle数据源(不同的模式),带有/不带有Ehcache,等等)。这就是从普通JDBC使用切换到JTA事务划分的原因。 > 在外部事务中使用Ehcache访问,在内部事务中只使用DB访问,即使在内部事务中使

  • 问题内容: 基本上我有(忽略异常处理等): 如果我理解正确,那应该不会有任何影响,因为它真正所做的只是为GC释放了资源。特别是对于Derby:不再需要语句,结果集和连接时,应明确关闭它们。与Derby的连接是应用程序外部的资源,并且垃圾收集器不会自动关闭它们。 但是,这会导致交易出现任何问题吗?我认为交易不依赖于该声明。有人可以确认吗? 问题答案: 绝对可以关闭它们,应该这样做。

  • 我在我的项目中做过类似的事情。我手动回滚事务,为此我插入了try-catch块并手动回滚catch块中的事务。现在我从method1调用method2,并将对象保存到method2()中的数据库中,但它不会将对象保存到数据库中。 我只是想知道什么是可能的解决方案,保存对象在方法2()在方法1()的faliure。 提前感谢。

  • 我无法使spring-Cloud-stream-binder-kafka适用于以下用例: 启动@事务(Rest控制器)DB更新/插入发送Kafka消息 在事务提交之前,使用者(使用@EnableBinding和@StreamListener配置)能够读取记录。此使用者已配置了read\u提交的隔离级别。 我不确定这是一个问题还是我这边的任何配置。 尝试配置bean ChainedTransacti

  • 以下是使用事务教程中描述的提交和回滚的代码示例。 此示例代码是基于前面章节中完成的环境和数据库设置编写的。 复制并将以下示例代码保存到:CommitAndRollback.java 中,编译并运行如下 - 编译并运行结果如下 -