事务

事务具有四个基本特征:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration),简称ACID

  • 原子性
    • 事务必须是一个原子的操作序列单元
    • 事务中包含的各项操作在一次执行过程中,只允许出现两种状态之一,要么都成功,要么都失败
    • 任何一项导致错误的操作都会导致整个事务的失败,同时其它已经被执行的操作都将被撤销并回滚,只有所有的操作全部成功,整个事务才算是成功完成
  • 一致性
    • 事务的执行不能破坏数据库数据的完整性和一致性
    • 一个事务在执行之前和执行之后,数据库都必须处以一致性状态
  • 隔离性
    • 在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰
    • 不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间
    • 事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的
  • 持久性
    • 事务一旦提交后,数据库中的数据必须被永久的保存下来
    • 即使服务器系统崩溃或服务器宕机等故障,只要数据库重启,那么一定能够将其恢复到事务成功结束后的状态

案例

魔理沙给灵梦转账514块的步骤:

  1. 魔理沙的余额-514
  2. 灵梦的余额+514

只要其中任何一个步骤失败了都算失败,更严重的是,如果步骤2失败了,相当于灵梦什么都没拿到,而魔理沙亏了514块

所以,需要保证转账的操作是一件事务

DTO:

1
2
3
4
5
6
7
8
9
10
11
export class CreateManagerDto {
name: string;
money: number;
}

// 转账数据
export class giveMoneyDto {
fromId: number; // 发起人
toId: number; // 接收人
money: number; // 转款
}

实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Manager {
@PrimaryGeneratedColumn()
id: number;

@Column()
name: string;

@Column()
money: number;
}

Controller:

1
2
3
4
5
// 转账操作接口
@Post('/giveMoney')
giveMoney(@Body() giveMoneyDto: giveMoneyDto) {
return this.managerService.giveMoney(giveMoneyDto);
}

Service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { Injectable } from '@nestjs/common';
import { CreateManagerDto, giveMoneyDto } from './dto/create-manager.dto';
import { UpdateManagerDto } from './dto/update-manager.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Manager } from './entities/manager.entity';
import { Repository } from 'typeorm';

@Injectable()
export class ManagerService {
constructor(
@InjectRepository(Manager) private readonly money: Repository<Manager>,
) {}

async giveMoney(giveMoneyDto: giveMoneyDto) {
console.log(giveMoneyDto);
try {
// 开启事务
return this.money.manager.transaction(async (m) => {
// 获取发起人
const from = await this.money.findOne({
where: {
id: giveMoneyDto.fromId,
},
});
// 获取收款人
const to = await this.money.findOne({
where: {
id: giveMoneyDto.toId,
},
});
// 判断余额是否充足
if (from.money >= giveMoneyDto.money) {
// 余额充足,使用事务进行更新操作,参数1:要改的实体 参数2:要改的内容
// 发起人的钱款减少
m.save(Manager, {
id: giveMoneyDto.fromId,
money: from.money - giveMoneyDto.money,
});
// 收款人的钱款增多
m.save(Manager, {
id: giveMoneyDto.toId,
money: to.money + giveMoneyDto.money,
});
return '转账成功';
} else {
return '余额不足,无法发起转账';
}
});
} catch (e) {
throw new Error(e);
}
}

// 省略...
}