也许是小弟太愚笨了!网上也有文章说明,可我还是很晕乎!
比如A表,用户A和用户B同向A表插入一条新记录.
生成主键ID为1001,这时候用户A和用户B同时持有这个主键ID,
向数据库插入就会引发冲突.我们在程序中如何解决这个问题呢?
也看过别人说锁表和事务控制,如何做呢?.以前写程序很少关注这个问题:(
都是 Insert into table1 values(...),然后就完了!没注意到并发的问题?
各位大哥,能给小弟具体说明下吗?预防并发冲突,如何做才好?
PS:如果大侠们懒得解释,给个文章链接也可以:)Thanks!
还有的就是如果用了ORM(LinQ,Ibatis,Hibernate,ETC)框架,这些问题又如何解决呢?
使用GUID作为主键而不是Int
兄弟能具体点吗?或者给个文章链接之类? 谢谢你的回复!
@kaleroy: 再次看了一下,你所问的应该是你的猜想而不是实际上遇到的吧,如果不需要做数据迁移的话继续用Int即可。在用户AB同时进行插入操作Insert into table1 values(...);Select @@Identity时,他们所持有的主键是不同的,要在插入的同时获取主键而不是插入完毕后再单独查询获取主键,那些框架也是这样做的,不用担心
@Lionheart Zhang:
非常感谢您的回复!嗯,那些是我猜想的...但实际上我也是在担心那些问题!
最后还有点问题:如果我的主键不是自增长,手动生成的呢?如何避免上述问题?
@kaleroy:加锁
-- 测试表
CREATE TABLE dbo.tb(
id int PRIMARY KEY
)
INSERT dbo.tb(id)
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3
GO
BEGIN TRAN
DECLARE
@id int
SELECT @id=max(id) FROM dbo.tb WITH(UPDLOCK, HOLDLOCK)
WAITFOR DELAY '00:00:10' -- 等待 10 秒, 这里可以放你的任何处理,实际使用时删掉该行
INSERT dbo.tb(id) values(@id+1)
COMMIT TRAN
GO
-- 更新用, 无法读取
SELECT max(id) FROM dbo.tb WITH(UPDLOCK, HOLDLOCK)
GO
-- 普通查询, 则可以读出数据
SELECT max(id) FROM dbo.tb
GO
@Lionheart Zhang:
明白!谢谢:)
我认为处理并发问题可以使用@@rowcount的全局变量作为if的判断条件,这样同时进来的人也可以对其进行并发操作,else报出 RAISERROR('ConcurrentUpdated', 16, 1)
RETURN @@ERROR
这个异常即可!
你的意思是如果并发冲突了,就报异常,根据异常来进行重试并处理.这个我能理解!
比如冲突了,就提示用户重试并引导用户解决问题,要么就系统自动处理!
请问 紫霖冰雨 兄,你推荐使用自动增长列呢?还是自己手动生成主键增长列?
哪样比较好?我觉得自动增长列使用不方便,比如数据导入麻烦,主键冲突等....
@kaleroy:
兄弟下次再给你分!