在下表中,存储了批量许可协议的记录
由客户购买。 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条这样的记录。
为了可靠地这样做,似乎我必须检查有多少许可证
可用和正在使用(通过选择VolumeLicenses
和
VolumeLicenseUsers
表),然后只要没有任何变化就执行INSERT
与此同时。
我可以使用什么SQL来进行此事务处理?理想情况下,我只会锁定
VolumeLicenses
LicenseId
中的单行,仅保护
VolumeLicenseUsers
表针对LicenseId
中的其他INSERTS表
问题
澄清
我并不是试图强制执行数据库完整性,就像伪CHECK CONSTRAINT一样。我只是在寻找一些能让我在不失一些竞争条件的情况下做到这一点的SQL。
答案 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,如果您有空许可证而不必担心另一个事务执行相同的操作,因为在第一个更新子句中将阻止对此的后续调用。