【开源库学习】libodb库学习(十一)

12 乐观并发

  • 只要我们在单个数据库事务中执行与特定应用程序事务对应的所有数据库操作,ODB事务模型(第3.5节,“事务”)就保证了一致性。也就是说,如果我们在数据库事务中加载一个对象并在同一事务中更新它,那么我们可以保证我们在数据库中更新的对象状态与我们加载的状态完全相同。换句话说,在这些加载和更新操作之间,另一个进程或线程不可能修改数据库中的对象状态。

  • 在本章中,我们使用术语应用程序事务来指代应用程序需要对持久对象执行的一组操作,以实现某些特定于应用程序的功能。术语数据库事务是指在ODB begin()commit()调用之间执行的一组数据库操作。到目前为止,我们基本上将应用程序事务和数据库事务视为同一件事。

  • 虽然此模型易于理解和使用,但它可能不适合具有长应用程序事务的应用程序。这种情况的典型示例是在加载对象和更新对象之间需要用户输入的应用程序事务。这样的操作可能需要任意长的时间才能完成,在单个数据库事务中执行它将消耗数据库资源,并阻止其他进程/线程长时间更新对象。

  • 这个问题的解决方案是将长期存在的应用程序事务分解为几个短期存在的数据库事务。在我们的示例中,这意味着在一个数据库事务中加载对象,等待用户输入,然后在另一个数据库交易中更新对象。例如:

unsigned long id = ...;
person p;{transaction t (db.begin ());db.load (id, p);t.commit ();
}cerr << "enter age for " << p.first () << " " << p.last () << endl;
unsigned short age;
cin >> age;
p.age (age);{transaction t (db.begin ());db.update (p);t.commit ();
}
  • 如果我们只有一个进程/线程可以更新对象,这种方法效果很好。然而,如果我们有多个进程/线程修改同一个对象,那么这种方法就不再保证一致性。考虑一下在上面的例子中,如果在我们等待用户输入的同时,另一个进程更新了该人的姓氏,会发生什么。由于我们在发生此更改之前加载了对象,因此我们版本的人员数据仍将使用旧名称。一旦我们收到用户的输入,我们就会继续更新对象,用新的(正确)覆盖旧的年龄,用旧的(不正确)覆盖新的名称。

  • 虽然无法在由多个数据库事务组成的应用程序事务中恢复一致性保证,但ODB提供了一种称为乐观并发的机制,允许应用程序检测并可能从这种不一致中恢复。

  • 本质上,乐观并发模型检测数据库中当前对象状态与加载到应用程序内存时的状态之间的不匹配。这种不匹配意味着对象被另一个进程或线程更改。有几种方法可以实现这种状态不匹配检测。目前,ODB使用对象版本控制,而未来可能会支持其他方法,如时间戳。

  • 为了用乐观并发模型声明一个持久类,我们使用optimistic pragma(第14.1.5节,“乐观”)。我们还使用version pragma(第14.4.16节,“version”)来指定哪个数据成员将存储对象版本。例如:

#pragma db object optimistic
class person
{...#pragma db versionunsigned long version_;
};
  • 版本数据成员由ODB管理。当对象被持久化时,它被初始化为1,每次更新时递增1。ODB不使用0版本值,应用程序可以将其用作特殊值,例如,表示对象是瞬态的。请注意,为了使乐观并发正常工作,在使对象持久化或从数据库加载它之后,应用程序不应修改版本成员,直到从数据库中删除此对象的状态。为了避免对version成员的任何意外修改,我们可以将其声明为const,例如:
#pragma db object optimistic
class person
{...#pragma db versionconst unsigned long version_;
};
  • 当我们调用database::update()函数(第3.10节,“更新持久对象”)并传递一个状态过时的对象时,会抛出odb::object_changed异常。此时,应用程序有两个恢复选项:它可以中止并可能重新启动应用程序事务,也可以从数据库中重新加载新的对象状态,重新应用或合并更改,并再次调用update()。请注意,中止在多个数据库事务中执行更新的应用程序事务可能需要还原已提交到数据库的更改。因此,如果所有更新都在应用程序事务的最后一个数据库事务中执行,则此策略效果最佳。这样,只需回滚最后一个数据库事务,就可以恢复更改。

  • 以下示例显示了如何使用第二个恢复选项重新实现上述事务:

unsigned long id = ...;
person p;{transaction t (db.begin ());db.load (id, p);t.commit ();
}cerr << "enter age for " << p.first () << " " << p.last () << endl;
unsigned short age;
cin >> age;
p.age (age);{transaction t (db.begin ());try{db.update (p);}catch (const object_changed&){db.reload (p);p.age (age);db.update (p);}t.commit ();
}
  • 在上面的代码片段中需要注意的一点是,第二次update()调用不能抛出object_changed异常,因为我们正在重新加载对象的状态并在同一个数据库事务中更新它。

  • 根据应用程序采用的恢复策略,更新失败的应用程序事务可能比成功的事务贵得多。因此,乐观并发最适合低到中等争用级别的情况,在这种情况下,大多数应用程序事务在没有更新冲突的情况下完成。这也是为什么这种并发模型被称为乐观的原因。

  • 除了更新,当我们从数据库中删除对象时,ODB还会执行状态不匹配检测(第3.11节,“删除持久对象”)。要理解为什么这很重要,请考虑以下应用程序事务:

unsigned long id = ...;
person p;{transaction t (db.begin ());db.load (id, p);t.commit ();
}string answer;
cerr << "age is " << p.age () << ", delete?" << endl;
getline (cin, answer);if (answer == "yes")
{transaction t (db.begin ());db.erase (p);t.commit ();
}
  • 再次考虑一下,如果在我们等待用户输入的同时,另一个进程或线程通过更改人的年龄来更新对象,会发生什么。在这种情况下,用户根据特定年龄做出决定,而我们可能会删除(或不删除)一个年龄完全不同的对象。以下是我们如何使用乐观并发来解决这个问题:
unsigned long id = ...;
person p;{transaction t (db.begin ());db.load (id, p);t.commit ();
}string answer;
for (bool done (false); !done; )
{if (answer.empty ())cerr << "age is " << p.age () << ", delete?" << endl;elsecerr << "age changed to " << p.age () << ", still delete?" << endl;getline (cin, answer);if (answer == "yes"){transaction t (db.begin ());try{db.erase (p);done = true;}catch (const object_changed&){db.reload (p);}t.commit ();}elsedone = true;
}
  • 请注意,只有当我们通过将对象实例传递给erase()函数删除对象时,才会执行状态不匹配检测。如果我们想删除一个具有乐观并发模型的对象,而不管它的状态如何,那么我们需要使用erase()函数来删除给定id的对象,例如:
{transaction t (db.begin ());db.erase (p.id ());t.commit ();
}
  • 最后,请注意,对于具有乐观并发模型的持久类,如果数据库中没有这样的对象,则update()函数和接受对象实例作为其参数的erase()函数都不再抛出object_not_persistent异常。相反,这种情况被视为对象状态的变化,并抛出object_changed异常。

  • 有关如何使用乐观并发的完整示例代码,请参阅odb-examples中的optimistic 示例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/49036.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习】机器学习解决的问题特点、机器学习学的是什么、怎么学、如何构建高效机器学习模型的策略、机器学习的分类以及机器学习、模式识别、数据挖掘和人工智能的区别

引言 机器学习是人工智能的一个重要分支&#xff0c;主要解决的是如何通过算法让机器从数据中自动学习规律和知识&#xff0c;以完成特定任务或解决特定问题。 文章目录 引言一、机器学习解决的是什么样的问题1.2 数据驱动的预测问题1.3 数据理解与挖掘1.4 优化与决策问题1.5 异…

如何开启或者关闭 Windows 安全登录?

什么是安全登录 什么是 Windows 安全登录呢&#xff1f;安全登录是 Windows 附加的一个组件&#xff0c;它可以在用户需要登录的之前先将登录界面隐藏&#xff0c;只有当用户按下 CtrlAltDelete 之后才出现登录屏幕&#xff0c;这样可以防止那些模拟登录界面的程序获取密码信息…

华为云技术精髓笔记(四)-CES基础入门实战

华为云技术精髓笔记(四) CES基础入门实战 一、监控ECS性能 1、 远程登录ECS 步骤一 双击实验桌面的“Xfce终端”打开Terminal&#xff0c;输入以下命令登录云服务器。注意&#xff1a;请使用云服务器的公网IP替换命令中的【EIP】。 LANGen_us.UTF-8 ssh rootEIP说明&#x…

ARM功耗管理之功耗和安全

安全之安全(security)博客目录导读 思考&#xff1a;功耗与安全&#xff1f;超频攻击&#xff1f;欠压攻击&#xff1f;低功耗流程中的安全&#xff1f; 睡眠唤醒流程中&#xff0c;安全相关寄存器的备份恢复 举例&#xff1a;比如某DMA通道&#xff0c;芯片逻辑默认为安全通…

centos/Ubuntu安装Nginx服务器

安装方式 使用系统自带的软件包管理器快速安装&#xff08;如centos的yum&#xff09;到官网下载压缩包安装&#xff08;https://nginx.org/en/download.html&#xff09;docker容器实例 下面是昨天以第二种方式安装的命令小记&#xff01; centos # 下载&#xff08;https…

使用原生 HTML + JS 实现类似 ChatGPT 的文字逐字显示效果

ChatGPT 的逐字显示效果很酷炫&#xff0c;那么我们可以尝试实现类似的效果。 定义一个基本 HTML 结构 <div class"chat-container"><div id"message"></div> </div>编写 JS 代码 const messageElement document.getElementBy…

压缩视频在线免费 怎么免费压缩视频大小 哪个软件可以免费压缩视频

在数字媒体时代&#xff0c;视频文件的体积越来越大&#xff0c;这就需要我们找到高效的方式来压缩视频&#xff0c;以节省存储空间和提升分享速度。本文将为您介绍几款免费的视频压缩软件&#xff0c;帮助您轻松应对视频文件管理难题。 方法一、 安装并打开一款的视频软件。 …

Git之repo sync -c与repo sync -dc用法区别四十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

解决云服务器CPU占用率接近100%问题

黑客通常利用云服务器开放的端口攻击云服务器&#xff0c;造成云服务器CPU占用率接近100%&#xff0c;云服务器CPU资源为黑客所用&#xff0c;例如&#xff1a;挖矿。 top命令查看资源使用情况 [hadoopMaster ~]$ top ...PID USER PR NI VIRT RES SHR S %CPU %…

【机器学习框架TensorFlow和PyTorch】基本使用指南

机器学习框架TensorFlow和PyTorch&#xff1a;基本使用指南 目录 引言TensorFlow概述 TensorFlow简介TensorFlow的基本使用 PyTorch概述 PyTorch简介PyTorch的基本使用 TensorFlow和PyTorch的对比结论 引言 随着深度学习的快速发展&#xff0c;机器学习框架在实际应用中起到…

idea springBoot启动时覆盖apollo配置中心的参数

vm options -Dorder.stat.corn“0/1 * * * * ?” 只有vm options, -D参数才能覆盖apollo参数 program arguments –key01val01 --key02val02 environment varibales envFAT;key02val02;key03val03

MySQL8.0新特性~最左前缀匹配原则被打破了

测试 在MySQL8.0.25和mysql5.7.33中创建如下 CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2)); INSERT INTO t1 VALUES(1,1), (1,2), (1,3), (1,4), (1,5),(2,1), (2,2), (2,3), (2,4), (2,5); INSERT INTO t1 SELECT f1, f2 5 FROM t1; INSERT I…

linux本地互传文件

1、从服务器下载文件 scp usernameservername:/remote_path/filename ~/local_destination 2、上传本地文件到服务器 scp ~/local_path/local_filename usernameservername:/remote_path 3、从服务器下载整个目录 scp -r usernameservername:/remote_path/remote_dir/ ~/loc…

面试题 33. 二叉搜索树的后序遍历序列

二叉搜索树的后序遍历序列 题目描述示例 题解递归单调栈 题目描述 输入一个整数数组&#xff0c;判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true&#xff0c;否则返回 false。假设输入的数组的任意两个数字都互不相同。 示例 参考以下这颗二叉搜索树&#…

【专题】百度萝卜快跑体验:Robotaxi发展现状与展望报告合集PDF分享(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p37054 百度“萝卜快跑”近期因事故与抵制引发关注&#xff0c;武汉部署超300辆全无人驾驶车。体验显示其安全但策略保守&#xff0c;行驶效率低于人类司机&#xff0c;价格亲民。阅读原文&#xff0c;获取专题报告合集全文&#xf…

Elastic 及阿里云 AI 搜索 Tech Day 将于 7 月 27 日在上海举办

活动主题 面向开发者的 AI 搜索相关技术分享&#xff0c;如 RAG、多模态搜索、向量检索等。 活动介绍 参加 Elastic 原厂与阿里云联合举办的 Generative AI 技术交流分享日。借助 The Elastic Search AI Platform&#xff0c; 使用开放且灵活的企业解决方案&#xff0c;以前所…

初学Mybatis之 Map 传参与模糊查询

实体类或数据库中的表&#xff0c;字段或参数过多&#xff0c;考虑使用 Map 接口里定义方法 int addUser(Map<String,Object> map); mapper.xml&#xff1a; parameterType 参数类型设置为 map sql 语句的 values 不一定要与数据库中的表字段相同 <insert id&quo…

Flink笔记整理(三)

Flink笔记整理&#xff08;三&#xff09; 文章目录 Flink笔记整理&#xff08;三&#xff09;五、DataStream API5.1Environment5.2 Source5.3 Transformation5.4 Sink 总结 五、DataStream API DataStream API是Flink的核心层API&#xff0c;一个Flink程序&#xff0c;其实本…

Java字符串最后一个单词的长度

题目要求 计算字符串最后一个单词的长度&#xff0c;单词以空格隔开&#xff0c;字符串长度小于5000。&#xff08;注&#xff1a;字符串末尾不以空格为结尾&#xff09; 示例1 输入&#xff1a;hello nowcoder 输出&#xff1a;8 说明&#xff1a;最后一个单词为nowcoder&…

数据库基础与性能概述及相关术语

在计算机科学领域&#xff0c;特别是数据库技术中&#xff0c;掌握与数据库性能相关的专业词汇对于数据库管理员、开发人员及数据分析师等专业人员来说至关重要。以下是一篇关于计算机必背单词——数据库性能相关的详细解析. 一、数据库基础与性能概述 数据库是计算机科学中的…