2016-06-28 8 views
0

"addUser"関数があり、 "Account"テーブルと "User"テーブルにレコードを挿入する必要があるので、2つのステップがトランザクション内になければならないため、私たちは「チーム」テーブルにレコードを挿入し、上記の関数を使用して管理者ユーザーを作成する必要があるの内側に、別の「addTeam」機能では、しかしネストされたトランザクションを扱う簡単な方法

function addUser (userName, password) { 
    sequelize.transaction(function() { 
     return AccountModel.create(...) 
     .then(UserModel.create(...))  
    }) 
} 

:以下のコードを記述します。この関数はまた、トランザクション内でラップする必要があります。

だから問題は、「アドユーザー」機能は、時には新しいトランザクションを開始し、そして時にはに渡されたトランザクションを使用する必要がありますする必要があり、来て最も明白な方法は以下の通りです:。もちろん

function addUser (userName, password, transaction) { 
     let func = function (t) { 
      return AccountModel.create(..., t) 
      .then(()=>UserModel.create(..., t))); 
     if (transaction) func(t); 
     else sequelize.transaction(x=>func(t)); 
} 

function addTeam() { 
    sequelize.transaction(x=> { 
     TeamModel.create(..., x) 
     .then(y=>addUser(x)); 
    }); 
} 

、それがありますひどい。簡単に、以下のように、発信者に対して完全に透過的にトランザクションを聞かせてそれに対処する方法:

@Transaction 
async function addUser(userName, password) { 
    await AccountModel.create(...); 
    await UserModel.create(...); 
} 

@Transaction 
async function addTeam(...) { 
    await TeamModel.create(...); 
    await addUser(...); 
} 

答えて

1

私は問題を解決し、素晴らしい気分です。

私はCLS機能sequelizeは、以下のコードのように、提供に使用:

let namespace = Sequelize.cls = cls.createNamespace('myschool'); 
export const db = new Sequelize(config.db.url); 

export const trans = option => operation => async function() { 
    let t = namespace.get('transaction'); 
    let hasTrans = !!t; 
    t = t || await db.transaction(); 
    try { 
     let result = await operation.apply(null, arguments); 
     if (!hasTrans) await t.commit(); 
     return result; 
    } 
    catch (e) { 
     if (!hasTrans) await t.rollback(); 
     throw e; 
    } 
}; 

上記のコードだけでトランザクションを作成し、ローカルコンテキスト内でトランザクションがない場合は、それをコミットし、それ以外の場合はちょうどそれを残します。

また、各業務機能は、取引をしたいだけで、以下のようにラップするために上記の高階関数を使用する必要があります。

export const createSchool = trans()(async (name, accountProps) => { 
    let school = await SchoolModel.create({name}); 
    let teacher = await createTeacher({...accountProps, schoolId: school.get('id')}); 
    return {school, teacher}; 
}); 
+0

は動作しません。 –

1

sequelize.transactionはoptionsオブジェクト受け入れる - options.transactionが設定されている場合、これはトランザクション内のセーブポイントを作成します(SQLの方言ことを提供)それをサポートしている、それ以外の場合は、だから、あなたは、単に

sequelize.transaction({ transaction }, x=>func(t)); 
を行うことができるはず

http://docs.sequelizejs.com/en/latest/api/sequelize/#transactionoptions-promise

新しいトランザクションを作成します。

+0

const cls = require('continuation-local-storage'); const Sequelize = require('sequelize'); const NAMESPACE = 'your-namespace'; // Use CLS for Sequelize Sequelize.cls = cls.createNamespace(NAMESPACE); const sequelize = new Sequelize(...); /* * * * * * * * * * * * * * * * * * * * * * THE MAGIC: Create a transaction wrapper * * * * * * * * * * * * * * * * * * * * */ function transaction(task) { return cls.getNamespace(NAMESPACE).get('transaction') ? task() : sequelize.transaction(task); }; /* * * * * * * * * * * * * * * * * * * * * * Your code below * * * * * * * * * * * * * * * * * * * * */ function addUser(userName, password) { return transaction(function() { return AccountModel .create(...) .then(() => UserModel.create(...)); }); } function addTeam() { return transaction(function() { return TeamModel .create(...) .then(() => addUser(...)); }); }

は、私が実際に取引が呼び出し側に透明にしたいが、あなたのソリューションはまだそれをkown発信者を必要とします。 – Ron

2

あなたがCLSを使用する場合は、非常に単純なヘルパー関数が作業を行います。

関連する問題