From 7ffc573d2e06a4a249b7932370672ec60051cabd Mon Sep 17 00:00:00 2001 From: xiong Date: Wed, 22 Jul 2026 15:03:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20SQLite=20=E9=92=B1?= =?UTF-8?q?=E5=8C=85=E8=B0=83=E8=B4=A6=E9=94=81=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/wallets/wallets.service.spec.ts | 51 +++++++++++++++++++ apps/server/src/wallets/wallets.service.ts | 11 ++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/apps/server/src/wallets/wallets.service.spec.ts b/apps/server/src/wallets/wallets.service.spec.ts index c730c62..adf919f 100644 --- a/apps/server/src/wallets/wallets.service.spec.ts +++ b/apps/server/src/wallets/wallets.service.spec.ts @@ -117,3 +117,54 @@ describe('WalletsService financial boundaries', () => { expect(dataSource.transaction).not.toHaveBeenCalled(); }); }); + +describe('WalletsService wallet locking', () => { + const createQueryManager = () => { + const wallet = { id: 1, studentId: 10, balance: 0 }; + const query = { + where: jest.fn(), + setLock: jest.fn(), + getOne: jest.fn(async () => wallet), + }; + query.where.mockReturnValue(query); + query.setLock.mockReturnValue(query); + return { + wallet, + query, + manager: { + createQueryBuilder: jest.fn(() => query), + findOne: jest.fn(), + }, + }; + }; + + it('skips pessimistic locking for SQLite', async () => { + const ctx = createQueryManager(); + const service = new WalletsService( + {} as any, + {} as any, + {} as any, + { options: { type: 'better-sqlite3' } } as any, + ); + + const result = await (service as any).getOrCreateWallet(ctx.manager, 10, true); + + expect(result).toBe(ctx.wallet); + expect(ctx.query.setLock).not.toHaveBeenCalled(); + expect(ctx.query.getOne).toHaveBeenCalled(); + }); + + it('keeps pessimistic write locking for MySQL', async () => { + const ctx = createQueryManager(); + const service = new WalletsService( + {} as any, + {} as any, + {} as any, + { options: { type: 'mysql' } } as any, + ); + + await (service as any).getOrCreateWallet(ctx.manager, 10, true); + + expect(ctx.query.setLock).toHaveBeenCalledWith('pessimistic_write'); + }); +}); diff --git a/apps/server/src/wallets/wallets.service.ts b/apps/server/src/wallets/wallets.service.ts index 1078446..270d2de 100644 --- a/apps/server/src/wallets/wallets.service.ts +++ b/apps/server/src/wallets/wallets.service.ts @@ -259,10 +259,13 @@ export class WalletsService { if (!lock || !manager.createQueryBuilder) { return manager.findOne(StudentWallet, { where: { studentId } }); } - return manager.createQueryBuilder(StudentWallet, 'wallet') - .where('wallet.studentId = :studentId', { studentId }) - .setLock('pessimistic_write') - .getOne(); + let query = manager + .createQueryBuilder(StudentWallet, 'wallet') + .where('wallet.studentId = :studentId', { studentId }); + if (['mysql', 'mariadb', 'postgres', 'cockroachdb'].includes(this.dataSource.options.type)) { + query = query.setLock('pessimistic_write'); + } + return query.getOne(); }; let wallet = await find(); if (!wallet) {