事 务

 

 

Oracle中的事务体现了所有必要的ACID特征。ACID是以下4个词的缩写:

l         原子性(atomicity) :事务中的所有动作要么都发生,要么都不发生。

l         一致性(consistency) :事务将数据库从一种一致状态转变为下一种一致状态。

l         隔离性(isolation) :一个事务的影响在该事务提交前对其他事务都不可见。

l         持久性(durability) :事务一旦提交,其结果就是永久性的。

 

8.1   事务控制语句

Oracle 中不需要专门的语句来“开始事务”。隐含地,事务会在修改数据的第一条语句处开始(也就是得到 TX 锁的第一条语句)。

可以使用哪些事务控制语句:

COMMIT:要想使用这个语句的最简形式,只需发出COMMIT

ROLLBACK:要想使用这个语句的最简形式,只需发出ROLLBACK

SAVEPOINTSAVEPOINT允许你在事务中创建一个“标记点”(marked point) ,一个事务中可以有多个SAVEPOINT

ROLLBACK TO <SAVEPOINT>:这个语句与SAVEPOINT命令一起使用。可以把事务回滚到标记点,而不回滚在此标记点之前的任何工作。

SET TRANSACTION:这条语句允许你设置不同的事务属性,如事务的隔离级别以及事务是只读的还是可读写的。使用手动undo管理时,还可以使用这个 来指示事务使用某个特定的 undo 段,不过不推荐这种做法。

 

8.2   原子性

8.2.1 语句级原子性

Oracle 保证最初的 INSERT(即导致触发器触发的插入语句)是原子性的,这个INSERT INTOT是语句,所以INSERT INTO T的任何副作用都被认为是语句的一部分。为了得到这种语句级原子性,Oracle悄悄地在每个数据库调用外面包了一个SAVEPOINT。前面的两个INSERT实际上处理如下:

Savepoint statement1;

Insert into t values ( 1 );

If error then rollback to statement1;

Savepoint statement2;

Insert into t values ( -1 );

If error then rollback to statement2;

Oracle中,这种语句级原子性可以根据需要延伸。在前面的例子中,如果INSERT INTO T触发了一个触发器,这个触发器会更新另一个表,而那个表也有一个触发器,它会删除第三个表(以此类推),那么要么所有工作都成功,要么无一成功。为保证这一点,无需你编写任何特殊的代码,Oracle本来就会这么做。

8.2.2 过程级原子性

OraclePL/SQL匿名块也当作是语句。

ops$tkyte@ORA10G> create or replace procedure p

2 as

3 begin

4 insert into t values ( 1 );

5 insert into t values (-1 );

6 end;

Oracle 把这个存储过程调用处理为一个原子语句。客户提交了一个代码块 BEGIN  P;  END;Oracle 在它外面包了一个SAVEPOINT。由于 P 失败了,Oracle 将数据库恢复到调用这个存储过程之前的时间点。下面,如果提交一个稍微不同的代码块,会得到完全不同的结果:

ops$tkyte@ORA10G> begin

2 p;

3 exception

4 when others then null;

5 end;

6 /

在此,我们运行的代码块会忽略所有错误,这两个代码块的输出结果有显著的差别。尽管前面第一个 P 调用没有带来任何改变,但在这里的P调用中,第一个INSERT会成功,而且T2中的CNT列会相应地递增。

Oracle把客户提交的代码块认为是“语句”。这个语句之所以会成功,因为它自行捕获并忽略了错误,所以If error then rollback…没有起作用,而且执行这个语句后Oracle没有回滚到SAVEPOINT。因此,这就保留了P完成的部分工作。为什么会保留这一部分工作呢?首要的原因是 P 中有语句级原子性:P 中的每条语句都具有原子性。P提交其两条 INSERT 语句时就成为 Oracle 的客户。每个INSERT 要么完全成功,要么完全失败。从以下事实就可以证明这一点:可以看到,T上的触发器触发了两次,而且将T2更新了两次,不过T2中的计数只反映了一个UPDATEP中执行的第二个INSERT外包着一个隐式的SAVEPOINT

 

8.2.3 事务级原子性

事务也是原子性的,事务完成的所有工作要么完全提交并成为永久性的,要么会回滚并撤销。

 

8.3   完整性约束和事务

需要指出到底什么时候检查完整性约束。默认情况下,完整性约束会在整个SQL语句得到处理之后才进行检查。也有一些可延迟的约束允许将完整性约束的验证延迟到应用请求时(发出一个 SET  CONSTRAINTS  ALL  IMMEDIATE 命令)才完成,或者延迟到发出

COMMIT时再检查。

8.3.1 MMEDIATE 约束

这是一般情况。在这种情况下,完整性约束会在整个SQL语句得到处理之后立即检查。注意,这里我用的是“SQL 语句”而不只是“语句”。如果一个 PL/SQL 存储过程中有多条 SQL 语句,那么在每条 SQL 语句执行之后都会立即验证其完整性约束,而不是在这个存储过程完成后才检查它。 那么,为什么约束要在 SQL 语句执行之后才验证呢?为什么不是在 SQL 语句执行期间验证?这是因为,一条语句可能会使表中的各行暂时地“不一致”(如SQL语句:update t set x=x+1),这是很自然的。尽管一条语句全部完成后的最终结果是对的,但如果查看这条语句所做的部分工作,会导致 Oracle拒绝这个结果。

 

8.3.2 DEFERRABLE 约束和级联更新

Oracle8.0开始,我们还能够延迟约束检查,对于许多操作来说,这很有好处。首先能想到的是,可能需要将一个主键的UPDATE级联到子键。也许很多人会说:这没有必要,因为主键是不可变的(我就是这些人之一),但是还有人坚持要有级联 UPDATE。有了可延迟的约束,就使得级联更新成为可能。

注意创建子表的语法如下(父表的创建略):

ops$tkyte@ORA10G> create table c

2 ( fk constraint c_fk

3 references p(pk)

4 deferrable

5 initially immediate

6 )

7 /

Table created.

这个约束创建为一个DEFERRABLE约束,但是设置为 INITIALLY  IMMEDIATE。这说明,可以把这个约束延迟到 COMMIT 或另外某个时间才检查。不过,默认情况下,这个约束在语句级验证。这是可延迟约束最常见的用法。大多数现有的应用不会在 COMMIT 语句上检查约束冲突,你最好也不要这么做。

迟延更新的方法如下:

ops$tkyte@ORA10G> set constraint c_fk deferred;

Constraint set.

ops$tkyte@ORA10G> update p set pk = 2;

1 row updated.

Commit complete. ops$tkyte@ORA10G> update c set fk = 2;

1 row updated.

ops$tkyte@ORA10G> set constraint c_fk immediate;

Constraint set.

ops$tkyte@ORA10G> commit;

这就是级联更新的做法。注意,要延迟一个约束,必须这样来创建它们:先将其删除,再重新创建约束,这样才能把不可延迟的约束改变为可延迟约束。

 

8.4   不好的事务习惯

一般的数据库认为锁是稀有资源,另外读取器会阻塞写入器,反之,写入器也会阻塞读取器。为了提高并发性,这些数据库希望你的事务越小越好,有时甚至会以数据完整性为代价来做到这一点。Oracle 则采用了完全不同的方法。事务总是隐式的,没有办法“自动提交”事务,除非应用专门实现。在Oracle中,每个事务都应该只在必要时才提交,而在此之前不能提交。事务的大小要根据需要而定。锁、阻塞等问题并不是决定事务大小的关键,数据完整性才是确定事务大小的根本。锁不是稀有资源,并发的数据读取器和数据写入器之间不存在竞争问题。这样在数据库中就能有健壮的事务。这些事务不必很短,而要根据需求有足够长的持续时间(但是不能不必要地太长)。事务不是为了方便计算机及其软件,而是为了保护你的数据。

一般不好的思维习惯:

l         频繁地提交大量小事务比处理和提交一个大事务更快,也更高效。

l         没有足够的undo空间。

但其实最好的方法是按业务过程的要求以适当的频度提交,并且相应地设置undo段大小。

 

8.4.1 在循环中提交

1. 性能影响

    如果进行大批量的更新删除操作,最好用一条SQL语句完成,而不要受惯性思维的影响进行批量的提交(如每100条提交一次),这样性能反而不好。

    下面再对这个讨论做个补充,给出一个对应的例子。应该记得在第7章中,我们讨论过写一致性的概念,并介绍了UPDATE语句如何导致重启动。 如果要针对一个行子集 (有一个WHERE  子句)执行先前的UPDATE语句,而其他用户正在修改这个UPDATEWHERE子句中使用的列,就可能需要使用一系列较小的事务而不是一个大事务,或者更适合在执行大量更新之前先锁定表。这样做的目标是减少出现重启动的机会。如果要UPDATE表中的大量行,这会导致我们使用LOCK TABLE命令。不过,根据我的经验,这种大量更新或大量删除(只有这些语句才可能遭遇重启动)都是独立完成的。一次性的大量更新或清除旧数据通常不会在活动高发期间完成。实际上,数据的清除根本不应受此影响,因为我们一般会使用某个日期字段来定位要清除的信息,而其他应用不会修改这个日期数据。

 

2. Snapshot Too Old错误

如果像前面的那个例子一样,你一边在读取表,一边在修改这个表,就会同时生成查询所需的 undo 信息。UPDATE 生成了undo信息,你的查询可能会利用这些undo信息来得到待更新数据的读一致视图。如果提交了所做的更新,就会允许系统重用刚刚填写的undo段空间。如果系统确实重用了undo段空间,擦除了旧的undo数据(查询随后要用到这些undo信息) ,你就有大麻烦了。SELECT会失败,UPDATE也会中途停止。(为什么?)这样就有了一个部分完成的逻辑事务,而且可能没有什么好办法来重启动

ORA-01555错误的例子会使更新处于一种完全未知的状态。有些工作已经做了,而有些还没有做。如果在游标的FOR循环中提交,要想避免ORA-01555,我绝对是无计可施。 ORA-30036 错误是可以避免的,只需在系统中分配适当的资源。通过设置正确的大小就可以避免这个错误;但是第一个错误(ORA-01555)则不然。另外,即使我未能避免 ORA-30036 错误,至少更新会回滚,数据库还是处于一种已知的一致状态,而不会半路停在某个大更新的中间。另外可以通过视图V$UNDOSTAT观察所生成的UNDO数量。

 

3. 可重启动的过程需要复杂的逻辑

如果采用“在逻辑事务结束之前提交”的方法,最验证的问题是:如果 UPDATE 半截失败了,这会经常将你的数据库置于一种未知的状态中。除非你提取对此做了规划,否则很难重启动这个失败的过程,让它从摔倒的地方再爬起来。所以要考虑编写可重启动的逻辑程序,但这可能会很复杂。

推荐的做法:力求简单。如果能在SQL中完成,那就在SQL里完成。如果不能在SQL中完成,就用PL/SQL实现。要用尽可能少的代码来完成,另外应当分配充分的资源。一定要考虑到万一出现错误会怎么样。应当正确地设置 undo 段的大小,比起编写一个可重启动的程序来说,前者要容易得多。

 

8.1 分布式事务

Oracle 有很多很好的特性,其中之一就是能够透明地处理分布式事务。Oracle中分布式事务的关键是数据库链接 (database link)。它使用了一个 2PC 协议来做到这一点。2PC 是一个分布式协议,如果一个修改影响到多个不同的数据库,2PC允许原子性地提交这个修改。在多个数据库之间的一个2PC事务中,其中一个数据库(通常是客户最初登录的那个数据库)会成为分布式事务的协调器。这个站点会询问其他站点是否已经准备好提交。实际上,这个站点会转向其他站点,问它们是否准备就绪。其他的每个站点会报告它的“就绪状态“(YESNO) 。如果只要有一个站点投票 NO,整个事务就会回滚。如果所有站点都投票 YES,站点协调器会广播一条消息,使每个站点上的提交成为永久性的。

    对于分布式事务,还存在一些限制(不过并不多),其中重要的限制如下:

l         不能在数据库链接上发出COMMIT。也就是说,不能发出COMMIT@remote_site。只能从发起事务的那个站点提交。

l         不能在数据库链接上完成 DDL。这是上一个问题带来的直接结果。DDL会提交,而除了发起事务的站点外,你不能从任何其他站点提交,所以不能在数据库链接上完成DDL

l         不能在数据库链接上发出SAVEPOINT。简单地说,不能在数据库链接发出任务事务控制语句。所有事务控制都有最初打开数据库链接的会话继承得来;对于事务中的分布式实例,不能有不同的事务控制。

 

8.5   自治事务

自治事务(autonomous transaction)允许你创建一个“事务中的事务” ,它能独立于其父事务提交或回滚。 自治事务提供了一种用PL/SQL控制事务的新方法,可以用于:

l         顶层匿名块;

l         本地(过程中的过程) 、独立或打包的函数和过程;

l         对象类型的方法;

l         数据库触发器。

例如:

ops$tkyte@ORA10G> create or replace procedure Autonomous_Insert

2 as

3 pragma autonomous_transaction;

4 begin

5 insert into t values ( 'Autonomous Insert' );

6 commit;

7 end;

8 /

Procedure created.

 

注意这里使用了pragma AUTONOMOUS_TRANSACTION。这个指令告诉数据库:执行这个过程时要作为一个新的自治事务来执行,而且独立于其父事务。

注意:pragma是一个编译器指令,这是一种编辑器执行某种编译选项的方法。还有其他一些pragma。参考PL/SQL编程手册,可以看到其索引中有pragma的一个列表。

 

总结一下,如果在一个“正常”的过程中 COMMIT,它不仅会持久保留自己的工作,也会使该会话中未完成的工作成为永久性的。不过,如果在一个自治事务过程中完成COMMIT,只会让这个过程本身的工作成为永久性的。

 

 

 

 

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
你是一名计算机专业的学生,在《移动应用开发》这门课中,你要完成一项课程设计,内容如下:《移动应用开发综合实践》课程设计任书 一、任概述 1、项目名称:我的笔记本 2、项目概述: 本项目需要设计开发一款类似印象笔记、OneNote 笔记等可以记录笔记的 APP。项目 需要基于 Android 技术开发。在项目中用户可以注册用户、登录、创建笔记本、记录笔记、 搜索笔记等功能。例如在 APP 中可以创建数学笔记本,笔记本中每篇笔记可以记录每堂课 的内容;例如创建工作笔记本,笔记本中可以记录每天的工作情况等。项目详细功能分为必 须完成的基本功能需求和选做的扩展功能需求。 3、基本功能需求(必须完成) 基本功能是用户可以通过以下为功能以文字的方式记录笔记内容。是必须完成开发的。 本课程需要完成以下基本功能,才能通过。 (1) 用户注册:新用户使用用户名、密码、进行注册,注册成功后拥有一个账号。 (2) 用户登录:用户通过用户名,密码登录。登录成功后可以使用自己的笔记本。 (3) 新建项目:用户在可以自己的笔记本中创建多个项目。例如考研资料收集,日常 ,Android 课程资料等等。 (4) 修改项目:可以修改项目的名称。 (5) 删除项目:可以将某个项目删除,如果该项目删除,则该项目下所有笔记都被删除。 (6) 新建笔记:用户可以在某个项目中创建笔记,须包含笔记名称,笔记内容,系统自 动获取保存笔记的最新保存时间。 (7) 修改笔记:可以对已存在的笔记标题、内容进行修改。 (8) 删除笔记:用户可以删除过期,不使用的笔记。 (9) 笔记搜索:可以按照关键词搜索笔记标题。4、扩展功能需求(选做) 在完成基础功能需求的前提下,完成下列功能可以加分,提升成绩!大家可以选做某个 大模块的所有功能,也可以选做某个大模块下的其中的子模块。 (1)笔记本数据采用基于网络存储的云笔记本。 基本功能需求中的数据可以存储在手机上,但这有个问题,即换了手机即使重新安装了 APP 也无法获取以前的笔记了。云笔记本即数据存储在服器上。用户使用任何一台安装 《我的笔记本》APP 的手机,登录成功后即可以从服器同步所有以前的笔记本与笔记内 容。新建的笔记本数据、修改的笔记本数据、删除的数据可以同步到服器上。 (2)图片笔记。 用户在笔记中可以记录图片笔记。其子功能如下: ①手机拍照上传图片,将图片存储在笔记中。 ②从照片库中选择图片,将图片存储在笔记本中。 ③图片编辑。可以对笔记中的图片进行编辑(缩放、旋转、翻转、剪切等功能) ④图片涂鸦。在图片上可以书写文字涂鸦记录心得等。 ⑤对图片中的文字进行 OCR 识别。提取图片中的文字,提取可以进行编辑然后记入或 存储在笔记中。 ⑥手写图片识别,识别提取图片中的手写文字,编辑后存入笔记中 (3)语音笔记 用户可以在笔记中进行手机录音,将语音识别成文字,编辑手存储在笔记中,其子功能 如下: ①手机录音。用户在 APP 中可以进行听课或会议录音。例如可以笔记本可以是“XX 会 议”。用户可以对会议进行录音,每 10 分钟一条录音,打开该笔记本可以列出所有录音列 表。每条录音包括:自动生成的标题,时长,录音时间等。例如:毕业设计第 1 条录音, 10 分钟,时间:2025-10-01。用户点击录音即可播放录音内容。 ②语音识别。用户选择某条录音,对录音内容进行识别后转成文字,编辑后存入笔记中。(4)定时提醒。 用户可以对某个笔记中的设置提醒,到达计划时间后 APP 弹屏可播放声音对用户 就进行提醒。 (5)收藏笔记。 用户可以对某些重要的笔记进行收藏,方便查到与回看。 二、任说明 (1)基本功能是必须要完成的。基本功能中数据可以存储在手机上(单机版),也可以使用 服器进行存储(云笔记)。单机版可以采用 sqlite 数据库存储。 (2)云笔记的服器端可以采用(JSP+Servlet+Tomcat)方式或 SpringBoot 或使用 Bmob 等网络开放平台。 (3)云笔记的实现架构,请自行查找参考相关文献,具体关键词可以通过“android http”,”Android post”方式、android+web 方式、Android 与服器、Bmob 等。 (4)评分说明:首先必须要完成所有基本功能。在完成基本功能的基础上完成扩展功能 或将基本功能数据采用云笔记的方式存储,才可以加分。 (5)界面在总体按照上述要求的基础上可自由设计,越美观越好。 (6)每 1 位同学为一组,每位同学必须独立完成本课程设计,不得抄袭复制他人成果。 否则不记成绩。 三、报告书要求 (1)课程报告书的标题,请标注开发的有哪些功能。标题内容格式: 我的笔记本(基本版) 我的笔记本(基本版+扩展版) (2)请根据报告书的要求,完成所有部分需要完成的内容,其中系统设计(功能有设计、 数据库设计)为必填项。 3 移动应用开发综合实践-任书(V1.2-2025.06.17) 制作者:陆培军 (3)认真完成课程设计报告书,报告书的第 4 部分,请按照课程设计报告书所给模板, 详细完成每个部分。详细给出功能描述,UML 设计图、文字说明、数据库设计(E-R 图、表) 并配以文字描述。 (4)报告书中代码部分,请给出核心代码,并对代码作注释与说明,可以不需要全部 代码。 (5)请在报告书中完成本项目的参考书目。 (6)请勿改动《报告书》的任何格式,严格按照模板要求。模板正文红色文字部分是 必须要完成,请使用“宋体、5 号字、1.5 倍行距”。代码请使用“Times New Roman 字 体,五号字体,1 倍行距”。请排版整齐。代码请使用 https://word.wd1x.com/,格式化 后截图,粘贴到报告书中。 在以上要求中,选做的部分可以不用全部完成,你分析并挑选一到两个最容易实现的要求完成,要求给出完整且能运行的代码,并且给出最后运行的示例
06-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值