찾다
데이터 베이스MySQL 튜토리얼MongoDB操作手册CRUD事务两步提交

MongoDB操作手册CRUD事务两步提交

Jun 07, 2016 pm 04:06 PM
crudmongodb사무구현하다제출하다

执行两步提交 概述 这部分提供了多记录更新或者多记录事务,使用两步提交来完成多记录写入的模板。另外,可以扩展此方法来提供rollback-like功能。 背景 MongoDB对于单条记录的操作是原子性的;但是涉及多条记录的操作却不是原子性的。由于记录可能是相当复杂

执行两步提交

概述

这部分提供了多记录更新或者多记录事务,使用两步提交来完成多记录写入的模板。另外,可以扩展此方法来提供rollback-like功能。

背景

MongoDB对于单条记录的操作是原子性的;但是涉及多条记录的操作却不是原子性的。由于记录可能是相当复杂,并且有内嵌记录,单记录原子性操作提供了实际中常用的必要支持。
除了单记录的原子性操作,还有许多情况需要多记录操作事务,当执行一个包含一些列操作的事务时,就有以下要求:
原子性:如果一个操作失败,事务中之前的操作需要回滚到之前的状态
一致性:如果一个重大失误,比如网络故障,硬件故障,中断了事务,数据库必须能够恢复到之前的状态
对于需要多记录操作的事务,可以在应用中实现两步提交的方法,来提供多记录更新支持。使用这种方法保证了一致性,并且万一出现错误,事务的执行状态是可恢复的。然而在这个过程中,记录处于未定的数据和状态。
注意:因为MongoDB只有单记录操作是原子性的,两步提交只能提供语义上的“类事务”功能。对于应用来说,使其能够回到在两步提交中的某个状态的中间数据或者回滚数据。

模板

考虑以下情景:

要将资金从账户A转移到账户B,在关系型数据库中,可以在一个事务中从A中减去资金,同时在B中加上。在MongoDB中,可以模拟两步提交来获得相同结果。

这个例子使用两个集合
1.accounts,用于存储账户信息
2.transactions,用于存储资金转移事务的信息

初始化账户信息

db.accounts.insert(
[
{ _id: "A", balance: 1000, pendingTransactions: [] },
{ _id: "B", balance: 1000, pendingTransactions: [] }
]
);

初始化转账记录

对于每次资金转移操作,将转账信息添加到transactions集合中,插入的记录包含以下信息:
source和destination字段,引用自ccounts集合中的_id字段
value字段,声明转移数值
state字段,表明当前转移状态,值可以是initial,pending, applied, done, canceling, 或者 canceled.
lastModified字段,反应最后修改日期

从A转账100到B,初始化transactions记录:
db.transactions.insert({ _id: 1, source: "A", destination: "B", value: 100, state: "initial", lastModified: new Date() });

使用两步提交进行转账

1.从transactions集合中,找到state为initial的记录。此时transactions集合中只有一条记录,即刚插入的那条。在包含其他记录的集合中,除非你声明了其他查询条件,否则这个查询将返回任何state为initial的记录。
var t = db.transactions.findOne( { state: "initial" } );
在MongoDB的shell中输入t,查看t的内容,类似于:
{ "_id" : 1, "source" : "A", "destination" : "B", "value" : 100, "state" : "initial", "lastModified":??}
2.更新事务状态为pending
设置state为pending,lastModified为当前时间
db.transactions.update(
{ _id: t._id, state: "initial" },
{
$set: { state: "pending" },
$currentDate: { lastModified: true }
}
)
在更新操作中,state:'initial'确保没有其他进程已经更新了这条记录。如果nMatched和nModified是0,回到第一步,获取一个新的事务,重新开始这个过程。
3.在两个账户中应用该事务
使用update方法将事务t应用到两个账户中。在更新条件中,包含条件pendingTransactions:{$ne:t._id},以避免重复应用该事务。
db.accounts.update(
{ _id: t.source, pendingTransactions: { $ne: t._id } },
{ $inc: { balance: -t.value }, $push: { pendingTransactions: t._id } }
)
db.accounts.update(
{ _id: t.destination, pendingTransactions: { $ne: t._id } },
{ $inc: { balance: t.value }, $push: { pendingTransactions: t._id } }
)
从A账号减去t.value,给B账户加上t.value,同时给每个账户的pendingTransactions数组添加事务id
4.更新事务状态为applied
db.transactions.update(
{ _id: t._id, state: "pending" },
{
$set: { state: "applied" },
$currentDate: { lastModified: true }
}
)
5.更新账户pendingTransactions数组
db.accounts.update(
{ _id: t.source, pendingTransactions: t._id },
{ $pull: { pendingTransactions: t._id } }
)
db.accounts.update(
{ _id: t.destination, pendingTransactions: t._id },
{ $pull: { pendingTransactions: t._id } }
)
从两个账户中移除已应用的事务。
6.更新事务状态为done
db.transactions.update(
{ _id: t._id, state: "applied" },
{
$set: { state: "done" },
$currentDate: { lastModified: true }
}
)

从失败场景中恢复数据

事务最重要的不是以上这个例子提供的原型,而是当事务没有完全执行成功的时候,从各种失败场景中恢复数据的可能性。
恢复操作
两步提交模型允许应用程序重新执行事务操作序列,以保证数据一致性。在程序启动时,或者定时执行恢复操作,来抓取任何未完成的事务。
恢复到数据一致的状态的时间取决于应用程序多久需要恢复每个事务。
以下恢复操作使用lastModified日期作为pending状态的事务是否需要回滚的标识符。如果pending或者applied状态的事务在最近的30分钟内没有被更新,说明这些事务需要被恢复。可以使用不同的条件来决定是否需要恢复。

Pending状态的事务

恢复事务状态在pending之后,applied之前
例:
获取三十分钟内未成功的事务记录
var dateThreshold = new Date();
dateThreshold.setMinutes(dateThreshold.getMinutes() - 30);
var t = db.transactions.findOne( { state: "pending", lastModified: { $lt: dateThreshold } } );
然后回到“3.在两个账户中应用该事务”这一步

Applied状态的事务

例:
获取三十分钟内未成功的事务记录
var dateThreshold = new Date();
dateThreshold.setMinutes(dateThreshold.getMinutes() - 30);
var t = db.transactions.findOne( { state: "applied", lastModified: { $lt: dateThreshold } } );
然后回到“5.更新账户pendingTransactions数组”这一步

回滚操作

有些情况下,可能需要回滚,或者撤销操作,比如,应用程序需要取消事务,或者其中一个账户不存在或者被冻结。

Applied状态的事务

在“4.更新事务状态为applied”这一步之后,不应该再回滚事务,而是应该完成当前事务,然后创建一个新的事务来把数据修改回来。

Pending状态的事务

在“2.更新事务状态为pending”这一步之后,“4.更新事务状态为applied”这一步之前,可以通过以下步骤回滚事务:
1.更新事务状态为取消中
db.transactions.update(
{ _id: t._id, state: "pending" },
{
$set: { state: "canceling" },
$currentDate: { lastModified: true }
}
)
2.在两个账户中取消操作
如果事务已经应用,需要回退这个事务以取消在两个账户上的操作。在更新的条件中,包含pendingTransactions:t._id,以便在pending transaction已经被应用的时候更新账户。
更新目标账户,减去事务中给其增加的值,cong pendingTransactions数组中移除事务_id
db.accounts.update(
{ _id: t.destination, pendingTransactions: t._id },
{
$inc: { balance: -t.value },
$pull: { pendingTransactions: t._id }
}
)
如果pending transaction还没有被应用到这个账户中,将不会有记录匹配查询条件。
3.更新事务状态为已取消
db.transactions.update(
{ _id: t._id, state: "canceling" },
{
$set: { state: "cancelled" },
$currentDate: { lastModified: true }
}
)
更新事务状态为cancelled来标志事务已取消。

多应用情景

由于事务的存在,多个应用可以同时创建和执行操作,而不会产生数据不一致或者冲突。在之前的例子中,更新或者回滚记录,包含state字段的更新条件防止不同应用重复提交事务
例如,app1和app2同时获取了一个在initial状态的事务。app1在app2开始前提交了整个事务。当app2试图更新事务状态为pending的时候,包含state:'initial'的更新条件将不会匹配任何记录,
同时nMatched和nModified将为0.这就表明app2需要回到第一步,重启一个不同的事务过程。
当多个应用运行的时候,关键在有只有一个应用可以及时处理指定的事务。这样的话,即使在有符合更新条件的记录,也可以在事务记录中创建一个标记来标志应用正在处理这个事务。使用findAndModify()方法来修改事务,并且回退。
t = db.transactions.findAndModify(
{
query: { state: "initial", application: { $exists: false } },
update:
{
$set: { state: "pending", application: "App1" },
$currentDate: { lastModified: true }
},
new: true
}
)
修正后的事务操作确保只有标识符匹配的应用可以提交该事务。
如果app1在事务执行中失败,可以使用之前讲的恢复操作,但是应用程序需要在应用事务之前确保“拥有”该事务。
例如,查找并恢复pending状态的job
var dateThreshold = new Date();
dateThreshold.setMinutes(dateThreshold.getMinutes() - 30);
db.transactions.find(
{
application: "App1",
state: "pending",
lastModified: { $lt: dateThreshold }
}
)

在生产环境中使用两步提交

以上的例子是有意写的很简单。例如,它假设一个账户的回滚操作总是可能的,并且账户可以保存负值。
生产环境可能会更加负值,通常来说,账户需要当前账户值,信用,欠款等多种信息。
对于所有事务,要确保使用的是write concern权限等级。
성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
MySQL의 장소 : 데이터베이스 및 프로그래밍MySQL의 장소 : 데이터베이스 및 프로그래밍Apr 13, 2025 am 12:18 AM

데이터베이스 및 프로그래밍에서 MySQL의 위치는 매우 중요합니다. 다양한 응용 프로그램 시나리오에서 널리 사용되는 오픈 소스 관계형 데이터베이스 관리 시스템입니다. 1) MySQL은 웹, 모바일 및 엔터프라이즈 레벨 시스템을 지원하는 효율적인 데이터 저장, 조직 및 검색 기능을 제공합니다. 2) 클라이언트 서버 아키텍처를 사용하고 여러 스토리지 엔진 및 인덱스 최적화를 지원합니다. 3) 기본 사용에는 테이블 작성 및 데이터 삽입이 포함되며 고급 사용에는 다중 테이블 조인 및 복잡한 쿼리가 포함됩니다. 4) SQL 구문 오류 및 성능 문제와 같은 자주 묻는 질문은 설명 명령 및 느린 쿼리 로그를 통해 디버깅 할 수 있습니다. 5) 성능 최적화 방법에는 인덱스의 합리적인 사용, 최적화 된 쿼리 및 캐시 사용이 포함됩니다. 모범 사례에는 거래 사용 및 준비된 체계가 포함됩니다

MySQL : 소기업에서 대기업에 이르기까지MySQL : 소기업에서 대기업에 이르기까지Apr 13, 2025 am 12:17 AM

MySQL은 소규모 및 대기업에 적합합니다. 1) 소기업은 고객 정보 저장과 같은 기본 데이터 관리에 MySQL을 사용할 수 있습니다. 2) 대기업은 MySQL을 사용하여 대규모 데이터 및 복잡한 비즈니스 로직을 처리하여 쿼리 성능 및 트랜잭션 처리를 최적화 할 수 있습니다.

Phantom은 무엇을 읽고, Innodb는 어떻게 그들을 막을 수 있습니까 (다음 키 잠금)?Phantom은 무엇을 읽고, Innodb는 어떻게 그들을 막을 수 있습니까 (다음 키 잠금)?Apr 13, 2025 am 12:16 AM

InnoDB는 팬텀 읽기를 차세대 점화 메커니즘을 통해 효과적으로 방지합니다. 1) Next-Keylocking은 Row Lock과 Gap Lock을 결합하여 레코드와 간격을 잠그기 위해 새로운 레코드가 삽입되지 않도록합니다. 2) 실제 응용 분야에서 쿼리를 최적화하고 격리 수준을 조정함으로써 잠금 경쟁을 줄이고 동시성 성능을 향상시킬 수 있습니다.

MySQL : 프로그래밍 언어는 아니지만 ...MySQL : 프로그래밍 언어는 아니지만 ...Apr 13, 2025 am 12:03 AM

MySQL은 프로그래밍 언어가 아니지만 쿼리 언어 SQL은 프로그래밍 언어의 특성을 가지고 있습니다. 1. SQL은 조건부 판단, 루프 및 가변 작업을 지원합니다. 2. 저장된 절차, 트리거 및 기능을 통해 사용자는 데이터베이스에서 복잡한 논리 작업을 수행 할 수 있습니다.

MySQL : 세계에서 가장 인기있는 데이터베이스 소개MySQL : 세계에서 가장 인기있는 데이터베이스 소개Apr 12, 2025 am 12:18 AM

MySQL은 오픈 소스 관계형 데이터베이스 관리 시스템으로, 주로 데이터를 신속하고 안정적으로 저장하고 검색하는 데 사용됩니다. 작업 원칙에는 클라이언트 요청, 쿼리 해상도, 쿼리 실행 및 반환 결과가 포함됩니다. 사용의 예로는 테이블 작성, 데이터 삽입 및 쿼리 및 조인 작업과 같은 고급 기능이 포함됩니다. 일반적인 오류에는 SQL 구문, 데이터 유형 및 권한이 포함되며 최적화 제안에는 인덱스 사용, 최적화 된 쿼리 및 테이블 분할이 포함됩니다.

MySQL의 중요성 : 데이터 저장 및 관리MySQL의 중요성 : 데이터 저장 및 관리Apr 12, 2025 am 12:18 AM

MySQL은 데이터 저장, 관리, 쿼리 및 보안에 적합한 오픈 소스 관계형 데이터베이스 관리 시스템입니다. 1. 다양한 운영 체제를 지원하며 웹 응용 프로그램 및 기타 필드에서 널리 사용됩니다. 2. 클라이언트-서버 아키텍처 및 다양한 스토리지 엔진을 통해 MySQL은 데이터를 효율적으로 처리합니다. 3. 기본 사용에는 데이터베이스 및 테이블 작성, 데이터 삽입, 쿼리 및 업데이트가 포함됩니다. 4. 고급 사용에는 복잡한 쿼리 및 저장 프로 시저가 포함됩니다. 5. 설명 진술을 통해 일반적인 오류를 디버깅 할 수 있습니다. 6. 성능 최적화에는 인덱스의 합리적인 사용 및 최적화 된 쿼리 문이 포함됩니다.

MySQL을 사용하는 이유는 무엇입니까? 혜택과 장점MySQL을 사용하는 이유는 무엇입니까? 혜택과 장점Apr 12, 2025 am 12:17 AM

MySQL은 성능, 신뢰성, 사용 편의성 및 커뮤니티 지원을 위해 선택됩니다. 1.MYSQL은 효율적인 데이터 저장 및 검색 기능을 제공하여 여러 데이터 유형 및 고급 쿼리 작업을 지원합니다. 2. 고객-서버 아키텍처 및 다중 스토리지 엔진을 채택하여 트랜잭션 및 쿼리 최적화를 지원합니다. 3. 사용하기 쉽고 다양한 운영 체제 및 프로그래밍 언어를 지원합니다. 4. 강력한 지역 사회 지원을 받고 풍부한 자원과 솔루션을 제공합니다.

InnoDB 잠금 장치 (공유 잠금, 독점 잠금, 의도 잠금, 레코드 잠금, 갭 잠금, 차세대 자물쇠)를 설명하십시오.InnoDB 잠금 장치 (공유 잠금, 독점 잠금, 의도 잠금, 레코드 잠금, 갭 잠금, 차세대 자물쇠)를 설명하십시오.Apr 12, 2025 am 12:16 AM

InnoDB의 잠금 장치에는 공유 잠금 장치, 독점 잠금, 의도 잠금 장치, 레코드 잠금, 갭 잠금 및 다음 키 잠금 장치가 포함됩니다. 1. 공유 잠금을 사용하면 다른 트랜잭션을 읽지 않고 트랜잭션이 데이터를 읽을 수 있습니다. 2. 독점 잠금은 다른 트랜잭션이 데이터를 읽고 수정하는 것을 방지합니다. 3. 의도 잠금은 잠금 효율을 최적화합니다. 4. 레코드 잠금 잠금 인덱스 레코드. 5. 갭 잠금 잠금 장치 색인 기록 간격. 6. 다음 키 잠금은 데이터 일관성을 보장하기 위해 레코드 잠금과 갭 잠금의 조합입니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

MinGW - Windows용 미니멀리스트 GNU

MinGW - Windows용 미니멀리스트 GNU

이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경