事务性SELECT和INSERT

时间:2015-07-30 17:05:17

标签: sql sql-server

在下表中,存储了批量许可协议的记录 由客户购买。 TotalLicenses列存储最大数量 允许使用该许可证激活的用户。

VolumeLicenses

+-----------+---------------+
| LicenseId | TotalLicenses |
+-----------+---------------+
|       901 |             3 |
|       902 |           100 |
|       903 |           150 |
+-----------+---------------+

另一个表存储使用每个许可证激活的用户:

VolumeLicenseUsers

+-----------+--------+
| LicenseId | UserId |
+-----------+--------+
|       901 | fred   |
|       901 | bob    |
|       901 | donna  |
|       902 | matt   |
|       902 | sarah  |
+-----------+--------+

在上面的例子中,我不能用a来插入另一条记录 901的LicenseId,因为已达到最大数量(3)。一世 但是,应该能够插入LicenseId为902的其他记录 直到表中有100条这样的记录。

为了可靠地这样做,似乎我必须检查有多少许可证 可用和正在使用(通过选择VolumeLicensesVolumeLicenseUsers表),然后只要没有任何变化就执行INSERT 与此同时。

我可以使用什么SQL来进行此事务处理?理想情况下,我只会锁定 VolumeLicenses LicenseId中的单行,仅保护 VolumeLicenseUsers表针对LicenseId中的其他INSERTS表 问题

澄清

我并不是试图强制执行数据库完整性,就像伪CHECK CONSTRAINT一样。我只是在寻找一些能让我在不失一些竞争条件的情况下做到这一点的SQL。

3 个答案:

答案 0 :(得分:0)

回答我自己的问题,但并非100%确定这是有效的, 事务讲....

DECLARE @UserId nvarchar(50) = 'john'
DECLARE @LicenseId int = 902

INSERT INTO dbo.VolumeLicenseUsers (LicenseId, UserId)
SELECT l.LicenseId, @UserId
FROM
    dbo.VolumeLicenses l 
    LEFT OUTER JOIN dbo.VolumeLicenseUsers u ON u.LicenseId = l.LicenseId
WHERE l.LicenseId = @LicenseId
GROUP BY l.LicenseId, l.TotalLicenses
HAVING COUNT(u.UserId) < l.TotalLicenses

-- Did it work?
SELECT * FROM dbo.VolumeLicenseUsers 
WHERE LicenseId = @LicenseId AND UserId = @UserId

答案 1 :(得分:0)

我不知道它是否真的是一个干净的解决方案:

1)开启交易

2)VolumeLicenseUsers

中添加记录

3)如果您拥有的许可数超过允许数量

,请签入VolumeLicenseUsers

4)如果not 3)commit其他rollback

可以吗?

答案 2 :(得分:0)

可能有更清洁的解决方案,但如果你这样做:

encodeNameReplacements

第一次更新虽然没有完成,但会在批量许可证上设置行锁定,以防止任何其他调用运行相同的逻辑,直到事务被回滚或提交。这允许您插入VolumeLicenseUsers,如果您有空许可证而不必担心另一个事务执行相同的操作,因为在第一个更新子句中将阻止对此的后续调用。