nestjs / TypeOrm数据库事务

时间:2018-12-08 07:56:51

标签: nestjs typeorm

假设我们有2个服务A和B。 服务A具有执行以下功能的功能:

  1. 验证数据
  2. 调用服务B函数,该函数对数据库进行更改
  3. 多做点事
  4. 对数据库进行更改

现在,让我们假设以下第3步或第4步之一失败了。 由于服务B在数据库中进行了更改,因此这些更改仍然存在。

在这种情况下,有什么办法可以回滚数据库?我虽然是关于数据库事务的,但是我在嵌套js中找不到任何方法可以做到这一点,尽管TypeOrm支持它,但是嵌套起来似乎并不自然。 如果没有,那么我现在就被服务B所发生的更改“卡住”了,但如果服务A发生了更改,我就不会被更改。

非常感谢。

4 个答案:

答案 0 :(得分:2)

有许多解决方案,它们都应基于SQL事务管理。

我个人认为,最简单的方法是在数据库上执行代码时使用相同的EntityManager实例。然后,您可以使用类似的内容:

getConnection().transaction(entityManager -> {
    service1.doStuff1(entityManager);
    service2.doStuff2(entityManager);
});

您可以从QueryRunner实例中产生一个EntityManager,该实例将包装在同一事务中,以防您在ORM操作之外执行原始SQL。您还需要从Repository生成EntityManager个实例,否则它们将在主事务之外执行代码。

答案 1 :(得分:2)

这是我解决问题的方法,因为我需要使用悲观锁。

我认为这是一种“巢式”的处理方式,您可以简单地要求NestJS注入Typeorm Connection的实例,那么您就很好了。

@Injectable()
class MyService {
  // 1. Inject the Typeorm Connection
  constructor(@InjectConnection() private connection: Connection) { }

  async findById(id: number): Promise<Thing> {
    return new Promise(resolve => {
      // 2. Do your business logic
      this.connection.transaction(async entityManager => {
        resolve(
          await entityManager.findOne(Thing, id, {
            lock: { mode: 'pessimistic_write' },
          }),
        );
      });
    });
  }
}

只需将所需的任何其他逻辑放入.transaction块中,就可以了。

注意:您必须使用entityManager方法提供的.transaction,否则它将不起作用。

答案 2 :(得分:1)

typeorm-transactional-cls-hooked使用CLS(连续本地存储)来处理和传播不同存储库和服务方法之间的事务。

@Injectable()
export class PostService {
  constructor(
    private readonly authorRepository: AuthorRepository,
    private readonly postRepository: PostRepository,
  ) {}

  @Transactional() // will open a transaction if one doesn't already exist
  async createPost(authorUsername: string, message: string): Promise<Post> {
    const author = await this.authorRepository.create({ username: authorUsername });
    return this.postRepository.save({ message, author_id: author.id });
  }
}

答案 3 :(得分:0)

在这种情况下,两个数据库操作必须使用相同的事务管理器。不幸的是,我没有示例存储库,但是我发现了在Node:

中使用Continuation Local Storage(CLS)的潜在解决方案。

https://github.com/typeorm/typeorm/issues/1895

这适用于Express.js,但您可以创建TransactionManager的实例(例如,在嵌套中间件中),并在每个请求上下文中存储它。然后,您可以在服务方法调用中重用此事务管理器,只要在上面的链接中使用@Transaction装饰器实现对其进行注释即可。

如果您的功能链中没有错误,则事务管理器将提交所有所做的更改。否则,经理将回滚所有更改。

希望这会有所帮助!