Sequelizejs's control of transactions, do you have any good suggestions for encapsulation?

use sequelizejs to control mysql transactions. How to encapsulate or design transactions across methods and service?

The framework of

application is express + sequelizejs,. In the service layer, it often appears in one method to call other service methods, but it is required to be in the same transaction, so you can only get the transaction and pass it to other service after opening the transaction. Once the service changes, there are a lot of things that need to be changed

.

for example, when saving an article on one side, you need to store the relationship of the tags it contains in another table, and the operation of saving the relationship between the tag and the article is in two service, so you need to pass the transaction

.
// 
async saveOrUpdateArticle(article: Article){
    if(!article.tags && article.tags.length < 1){
        throw new BusinessException("")
    }
    const result = await db.transaction().then(async (t) => {
        try {
            // 
            if(article.id){
                article.updateAt = Date.now();
                let originArticel = await this.getArticleById(article.id, t);
                originArticel = await originArticel.update(article, {transaction: t});
                //articleTag
            }else{
                // 
                const newArticle = await ArticleModel.create(article, {transaction: t});
                //throw "abort the transaction";
                const articleTags = [];
                article.tags.forEach((tagId) => {
                    const articleTag: ArticleTag = {
                        articelId: newArticle.id,
                        tagId: tagId
                    };
                    articleTags.push(articleTag);
                });
                // articleTag
                await this.services.articleTagService.saveOrUpdateArticleTags(articleTags, t);
            }
            await t.commit();
            return true;
        } catch (e) {
            await t.rollback()
            logger.error(e);
            return false;
        }   
    })
    return result;             
}

//     

async saveOrUpdateArticleTags(articleTags: ArticleTag[], t){
    const promiseList = [];
    articleTags.forEach((articleTag) => {
        promiseList.push(this.saveOrUpdateArticleTag(articleTag, t));
    });
    return await Promise.all(promiseList);
}

async saveOrUpdateArticleTag(articleTag: ArticleTag, t){
    //
    if(articleTag.id){
        articleTag.updateAt = Date.now();
        const originArticleTag = await this.getTagById(articleTag.id);
        if(!originArticleTag){
            throw new BusinessException(`id"${articleTag.id}"articleTag`);
        }
        articleTag = await originArticleTag.update(articleTag);
    }else{
        articleTag = await ArticleTagModel.create(articleTag, {transaction: t})
    }
    return articleTag;
}

when doing transaction operations, can you pass the transaction without parameters? do you have any good suggestions?


let transactionServer = new Server(t);
let server = new Server();

transactionServer.doSomething();

I also want to know if there is any good way, which is what we are doing at present.


without parameter passing, it can be understood that there is a "global variable" at work.

  1. each req triggers a docker rebuild and sets the global.transaction. However, it is certainly not suitable for existing projects, and it is possible to implement
  2. with serverless.
  3. set the req.transaction variable to ensure that the req variable is available in each operation. In this case, it is equivalent to using req to disguise the global variable

it is recommended not to use transactions of the database itself

Menu