transaction と bulk
- トランザクション: 一連のデータベース操作。操作の整合性を保証
- バルク操作: 大量のデータを一度に処理するための方法。処理の効率を高める
基本的なトランザクションの使用例
try {
await prisma.$transaction(async (prisma) => {
// 1つ目の操作: ユーザーを作成
const user = await prisma.user.create({
data: {
name: 'Alice',
email: 'alice@example.com',
},
});
// 2つ目の操作: ユーザーのプロフィールを作成
await prisma.profile.create({
data: {
userId: user.id,
bio: 'Hello, I am Alice!',
},
});
// 3つ目の操作: さらに他の操作をここで実行できます
});
console.log('Transaction completed successfully.');
} catch (error) {
console.error('Transaction failed: ', error);
} finally {
await prisma.$disconnect();
}
バルク操作
Prismaの標準のAPIにはバルク操作を直接サポートする機能はありません。
「トランザクション」もしくは「Raw SQL」を使用して一括操作できる
Raw SQL: prisma.$executeRaw
または prisma.$queryRaw
を利用して、SQLの構文を直接使用する方法
prisma.$executeRaw
: データベースに対する変更操作(INSERT, UPDATE, DELETE など)を実行し、結果として変更された行数などを返す。結果セットは返さない。
prisma.$queryRaw
: データベースからデータを取得する操作(SELECT など)を実行し、結果セットを返す。
bulk insert トランザクション
async function bulkInsert() {
const data = [
{ id: 1, name: 'Item1' },
{ id: 2, name: 'Item2' },
{ id: 3, name: 'Item3' },
];
try {
await prisma.$transaction(
data.map(item =>
prisma.your_table_name.create({
data: item,
})
)
);
console.log('Bulk insert completed successfully.');
} catch (error) {
console.error('Bulk insert failed: ', error);
} finally {
await prisma.$disconnect();
}
}
以下のようなSQL文を生成
BEGIN;
INSERT INTO your_table_name (id, name) VALUES (1, 'Item1');
INSERT INTO your_table_name (id, name) VALUES (2, 'Item2');
INSERT INTO your_table_name (id, name) VALUES (3, 'Item3');
COMMIT;
createMany 使えよ
async function bulkInsert() {
const employees = [
{ name: 'Alice', position: 'Engineer' },
{ name: 'Bob', position: 'Manager' },
{ name: 'Charlie', position: 'Analyst' },
];
try {
await prisma.employee.createMany({
data: employees,
skipDuplicates: true, // 重複をスキップするオプション。主キーが重複した場合にエラーを防ぐ
});
console.log('Bulk insert completed successfully.');
} catch (error) {
console.error('Bulk insert failed: ', error);
} finally {
await prisma.$disconnect();
}
}
以下のようなSQL文を生成
BEGIN;
INSERT INTO your_table_name (id, name) VALUES (1, 'Item1'), (2, 'Item2'), (3, 'Item3'), (4, 'Item4')
COMMIT;
bulk update トランザクション
async function bulkUpdate() {
const updates = [
{ id: 1, data: { name: 'UpdatedName1' } },
{ id: 2, data: { name: 'UpdatedName2' } },
{ id: 3, data: { name: 'UpdatedName3' } },
];
try {
await prisma.$transaction(
updates.map(update =>
prisma.your_table_name.update({
where: { id: update.id },
data: update.data,
})
)
);
console.log('Bulk update completed successfully.');
} catch (error) {
console.error('Bulk update failed: ', error);
} finally {
await prisma.$disconnect();
}
}
以下のようなSQL文を生成
BEGIN
SELECT id FROM your_table_name WHERE (id = ? AND 1=1)
UPDATE your_table_name SET name = 'UpdatedName1' WHERE (id IN (1) AND (id = 1 AND 1=1))
SELECT id, name FROM your_table_name WHERE id = 1 LIMIT ? OFFSET ?
SELECT id FROM your_table_name WHERE (id = ? AND 1=1)
UPDATE your_table_name SET name = 'UpdatedName2' WHERE (id IN (2) AND (id = 2 AND 1=1))
SELECT id, name FROM your_table_name WHERE id = 2 LIMIT ? OFFSET ?
SELECT id FROM your_table_name WHERE (id = ? AND 1=1)
UPDATE your_table_name SET name = 'UpdatedName3' WHERE (id IN (3) AND (id = 3 AND 1=1))
SELECT id, name FROM your_table_name WHERE id = 3 LIMIT ? OFFSET ?
COMMIT
updateMany 使えよ
app.get('/bulk_test/update2', async(req,res)=>{
const updates = [
{ id: 2, data: { score: 83 } },
{ id: 5, data: { score: 91 } },
];
try {
for (const update of updates) {
await prisma.your_table_name.updateMany({
where: { id: update.id },
data: update.data,
});
}
console.log('Bulk update completed successfully.');
} catch (error) {
console.error('Bulk update failed: ', error);
} finally {
res.send("BULK !")
}
});
以下のようなSQL文を生成
BEGIN
UPDATE your_table_name SET score = 83 WHERE id = 2
COMMIT
BEGIN
UPDATE your_table_name SET score = 91 WHERE id = 5
COMMIT
updateMany
は複数レコードに同じデータで更新することが出来る関数であり、複数レコードに異なるデータで更新する関数ではない。
updateMany をもっとうまく使う
try {
await prisma.$transaction([
prisma.item.updateMany({
where: { id: 2 },
data: { score: 84 },
}),
prisma.item.updateMany({
where: { id: 5 },
data: { score: 92 },
}),
]);
console.log('Bulk update completed successfully.');
} catch (error) {
console.error('Bulk update failed: ', error);
} finally {
await prisma.$disconnect();
}
以下のようなSQL文を生成
BEGIN;
UPDATE "Item"
SET "score" = 84
WHERE "id" = 2;
UPDATE "Item"
SET "score" = 92
WHERE "id" = 5;
COMMIT;
prisma ではできない理想
UPDATE your_table_name
SET data = JSON_SET(data, '$.score', CASE id
WHEN 2 THEN 83
WHEN 5 THEN 91
WHEN 7 THEN 92
WHEN 8 THEN 78
ELSE data
END)
WHERE id IN (2, 5, 7, 8);
upsert トランザクション
const upserts = data.map(item => prisma.your_table_name.upsert({
where: { id: item.id },
update: { /* 更新するフィールド */ },
create: { /* 新規作成するフィールド */ },
}));
const result = await prisma.$transaction(upserts);
console.log(result.length);
サンプル
const userList = [
{ email: 'alice@example.com', name: 'Alice' },
{ email: 'bob@example.com', name: 'Bob' },
{ email: 'charlie@example.com', name: 'Charlie' },
];
const upserts = userList.map(item => prisma.your_table_name.upsert({
where: { email: item.email, },
update: { name: user.name, },
create: {
email: user.email,
name: user.name,
},
}));
await prisma.$transaction(upserts);
以下のようなSQL文を生成
-- For email = 'alice@example.com'
INSERT INTO `User` (`email`, `name`)
VALUES ('alice@example.com', 'Alice')
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`);
-- For email = 'bob@example.com'
INSERT INTO `User` (`email`, `name`)
VALUES ('bob@example.com', 'Bob')
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`);
-- For email = 'charlie@example.com'
INSERT INTO `User` (`email`, `name`)
VALUES ('charlie@example.com', 'Charlie')
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`);
upsert Raw SQL
// const data = [/* 挿入または更新するデータの配列 */];
const data = [
{ id: 1, field1: 'Item11', field2: 'Item21' },
{ id: 2, field1: 'Item12', field2: 'Item22' },
{ id: 3, field1: 'Item13', field2: 'Item23' },
];
const query = `
INSERT INTO your_table (id, field1, field2)
VALUES ${data.map(item => `(${item.id}, '${item.field1}', '${item.field2}')`).join(', ')}
ON DUPLICATE KEY UPDATE
field1 = VALUES(field1),
field2 = VALUES(field2)
`;
try {
await prisma.$executeRaw(query);
console.log('Bulk upsert completed successfully.');
} catch (error) {
console.error('Bulk upsert failed: ', error);
} finally {
await prisma.$disconnect();
}
Prismaが生成するSQL文を確認する
Prismaのログ機能を使用する
クエリのログをコンソールに出力する機能
// Prisma Clientを設定する際に、logオプションを使用してログレベルを指定。
const prisma = new PrismaClient({
log: ['query', 'info', 'warn', 'error']
});