如果你只看数据库,一切都很好。您有事务,如果出现问题,一切都会回滚。这很好 - 我喜欢这个。
但是:我想发送邮件。现在我遇到了麻烦,因为我无法回滚。
例子:
如何解决这个问题是另一个问题,而不是这个问题。
这个问题一般怎么称呼这个。在这个例子中是关于发送邮件。但是,一旦您在事务边界之外的系统中修改某些内容,就会出现同样的问题。
这个问题有名字吗?
如果您想从目录中导入文件,大致会出现同样的问题。如果您删除事务内的文件,则事务可能会失败并且文件被删除但从未导入。或者您在交易后删除该文件。然后文件的删除可能会失败,并且该文件会再次导入。
我不想为此重新发明解决方案。这就是为什么我需要这个问题的匹配项。然后我可以阅读一些论文,了解什么是 2018 年的“最新技术”。
Oracle PL/SQL 关键字AUTONOMOUS_TRANSACTION将导致过程创建另一个会话、执行事务、提交/回滚该私有事务,并将流控制返回给父级。
哦..永远不要就未提交的数据发送电子邮件。
如果您想从目录中导入文件,大致会出现同样的问题。如果您删除事务内的文件,则事务可能会失败并且文件被删除但从未导入。或者您在交易后删除该文件。然后文件的删除可能会失败,并且该文件会再次导入。
这种类型的问题称为bug.
解决办法是:
TRANSACTION
COMMIT。你应该有一个sendEmail应该在之后调用的过程commit。
如果您想在 之前调用该过程commit,则需要将一行添加到将rollback包含主事务的队列中。对于 Oracle,这将是Advance Queuing或包APEX_MAIL
通过将其放在单独的程序中,您可以sendEmail根据 [最终用户的] 请求进行第二次。
您有一个包含几个步骤的算法,其中每个步骤都可能失败。这实际上与您的sendEmail问题不同。
您需要记录您正在处理的内容、您在算法中所处的位置以及该步骤是成功还是失败。
为了从任何步骤的错误中恢复,过程的每个步骤都需要定义为一个离散的TRANSACTION。
在 Oracle 中,我会有这些程序(每个程序 1 个程序TRANSACTION):
create or replace
package file_processing_package
as
procedure update_file_processing_status(
p_id IN files_to_process.id%TYPE
, p_status IN process_states.id%TYPE);
function add_a_file_to_be_processed( p_filename IN files_to_process.file_name%TYPE )
return files_to_process.id%TYPE;
procedure load_data_from_file( p_id in files_to_process.id%TYPE );
procedure process_already_loaded_data( p_id in files_to_process.id%TYPE );
procedure delete_file_from_os( p_id in files_to_process.id%TYPE );
end;
/
Run Code Online (Sandbox Code Playgroud)
这是基于下表:
CREATE TABLE PROCESS_STATES (
id int generate by default on null as identity, -- 12c+
state_desc varchar2(25) not null,
constraint process_states_pk primary key (id),
constraint process_states_uq1 unique (state_desc)
);
insert into process_states( state_desc ) values ( 'file to be processed' );
insert into process_states( state_desc ) values ( 'file loaded' );
insert into process_states( state_desc ) values ( 'processing' );
insert into process_states( state_desc ) values ( 'processing failed' );
insert into process_states( state_desc ) values ( 'processing succeeded' );
insert into process_states( state_desc ) values ( 'delete failed' );
insert into process_states( state_desc ) values ( 'OK' ); -- delete succeeded
commit;
CREATE TABLE FILES_TO_PROCESS (
id int generate by default on null as identity, -- 12c+
file_name varchar2(50) not null,
process_state_id int not null,
constraint file_to_process_pk primary key (id),
constraint file_to_process_uq1 unique (file_name),
constraint file_to_process_fk1 foreign key (process_state_id)
references (process_states.id)
);
Run Code Online (Sandbox Code Playgroud)
的UNIQUE约束FILE_NAME防止同一文件被处理两次。