sql 事务

maocheng82 2015-11-04 05:25:29
请教一个问题 比如我写个进销存 某个料号现在库存数量是300,假设有两个用户同时操作,一个入了300.另外一个入了200 这个时候系统的库存数据不是800 而是600或500 所以为了杜绝这种情况
用到了事务
begin tran
string sql = " update tb set sl=sl+入库数量 where partno=物料号 WITH (HOLDLOCK) ";
.....
commit tran



SQL执行语句 加了条 WITH (HOLDLOCK) 是不是可以杜鹃这个情况发生了 大家是如何解决的呢???
小弟对 WITH (HOLDLOCK) 研究的不是很深刻 望大家指教
...全文
232 点赞 收藏 21
写回复
21 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
misterliwei 2015-11-09
引用 18 楼 Tiger_Zhao 的回复:
有唯一索引不用用加锁,舍近求远!


试了一下:
IF OBJECT_ID('TA') IS NOT NULL
DROP TABLE TA
GO
CREATE TABLE TA(ID INT PRIMARY KEY, COL1 DATETIME)
GO
INSERT INTO TA VALUES(1, GETDATE())
GO


结果如下:
回复
Tiger_Zhao 2015-11-09
有唯一索引不用用加锁,舍近求远!
回复
misterliwei 2015-11-09
我认为是的。
回复
hunter_wyh 2015-11-09
引用 15 楼 misterliwei的回复:
查看了邹建的书,代码如下:

IF OBJECT_ID('TB') IS NOT NULL
DROP TABLE TB
GO

IF OBJECT_ID('F_NEXTBH') IS NOT NULL
DROP FUNCTION F_NEXTBH
GO

CREATE FUNCTION F_NEXTBH()
RETURNS CHAR(8)
AS BEGIN
RETURN (
SELECT 'BH' + RIGHT(1000001 + ISNULL(RIGHT(MAX(BH), 6), 0), 6)
FROM TB WITH(XLOCK, PAGLOCK))
END
GO
CREATE TABLE TB(BH CHAR(8) PRIMARY KEY DEFAULT DBO.F_NEXTBH(),
COL1 INT)
GO

BEGIN TRAN
INSERT INTO TB(COL1) VALUES(1)
INSERT INTO TB(COL1) VALUES(3)

DELETE TB WHERE COL1 = 3
INSERT INTO TB
VALUES(DBO.F_NEXTBH(), 14)
COMMIT TRAN
GO

SELECT * FROM TB
GO


20个线程同时执行20遍,没有发生错误.
所以说,一定要上锁,才能防止异步读取?
回复
xiaoxiangqing 2015-11-07
我觉得不用加,update时会锁的
回复
misterliwei 2015-11-07
引用 16 楼 xiaoxiangqing 的回复:
我觉得不用加,update时会锁的
#12楼就是没有加的实验,结果有很多重复值。
回复
misterliwei 2015-11-06
我测试几个方法,然后回答你。
回复
misterliwei 2015-11-06
查看了邹建的书,代码如下:

IF OBJECT_ID('TB') IS NOT NULL
DROP TABLE TB
GO

IF OBJECT_ID('F_NEXTBH') IS NOT NULL
DROP FUNCTION F_NEXTBH
GO

CREATE FUNCTION F_NEXTBH()
RETURNS CHAR(8)
AS BEGIN
RETURN (
SELECT 'BH' + RIGHT(1000001 + ISNULL(RIGHT(MAX(BH), 6), 0), 6)
FROM TB WITH(XLOCK, PAGLOCK))
END
GO
CREATE TABLE TB(BH CHAR(8) PRIMARY KEY DEFAULT DBO.F_NEXTBH(),
COL1 INT)
GO

BEGIN TRAN
INSERT INTO TB(COL1) VALUES(1)
INSERT INTO TB(COL1) VALUES(3)

DELETE TB WHERE COL1 = 3
INSERT INTO TB
VALUES(DBO.F_NEXTBH(), 14)
COMMIT TRAN
GO

SELECT * FROM TB
GO


20个线程同时执行20遍,没有发生错误.

回复
misterliwei 2015-11-06
引用 13 楼 Tiger_Zhao 的回复:
唯一索引呢?
添加唯一索引报重复插入错误。
回复
Tiger_Zhao 2015-11-06
唯一索引呢?
回复
misterliwei 2015-11-06
引用 11 楼 Tiger_Zhao 的回复:
[Quote=引用 9 楼 maocheng82 的回复:]
          string sql = "select  max(cast(replace(serialno,'T','') as int)) from TuiHuoRuKu ";
string serialno = DbHelperSQL.GetMax(sql) + 1).ToString()
StringBuilder strSql = new StringBuilder();
string sql1="insert into TuiHuoRuKu Values(+’”serialno+“‘......................
[/Quote]
用一个语句就可以完成的。单句操作不需要手动加锁。
insert into TuiHuoRuKu  
SELECT t.serialno, 字段值2, 字段值3, 字段值4, ...
FROM (
select ISNULL(max(cast(replace(serialno,'T','') as int)),0)+1 serialno
from TuiHuoRuKu
) t


根据你的方法,做了个测试:

IF OBJECT_ID('TA') IS NOT NULL
DROP TABLE TA
GO
CREATE TABLE TA(ID INT, COL1 DATETIME)
GO
INSERT INTO TA VALUES(1, GETDATE())
GO


然后10个线程同时执行10次,


结果发现好多重复值。

回复
Tiger_Zhao 2015-11-06
[Quote=引用 9 楼 maocheng82 的回复:]
          string sql = "select  max(cast(replace(serialno,'T','') as int)) from TuiHuoRuKu ";
string serialno = DbHelperSQL.GetMax(sql) + 1).ToString()
StringBuilder strSql = new StringBuilder();
string sql1="insert into TuiHuoRuKu Values(+’”serialno+“‘......................
[/Quote]
用一个语句就可以完成的。单句操作不需要手动加锁。
insert into TuiHuoRuKu  
SELECT t.serialno, 字段值2, 字段值3, 字段值4, ...
FROM (
select ISNULL(max(cast(replace(serialno,'T','') as int)),0)+1 serialno
from TuiHuoRuKu
) t
回复
maocheng82 2015-11-05
引用 5 楼 misterliwei 的回复:
首先没有使用BEGIN TRAN/ROLLBACK/COMMIT时,使用默认事务,一个UPDATE就是一个事务。 其次UPDATE会申请X锁,只有申请到该锁,才更新,并且X锁直到事务结束才释放。
那请教哈 比如 不是UPDATE 是select 或insert ,执行的时候是不是也是一个事务,在执行的SQL语句后面加上WITH (HOLDLOCK) 是不是在这个过程中其他人是访问不了该表中数据的??
回复
maocheng82 2015-11-05
引用 7 楼 wangjinlong_wjl 的回复:
[quote=引用 6 楼 maocheng82 的回复:] [quote=引用 5 楼 misterliwei 的回复:] 首先没有使用BEGIN TRAN/ROLLBACK/COMMIT时,使用默认事务,一个UPDATE就是一个事务。 其次UPDATE会申请X锁,只有申请到该锁,才更新,并且X锁直到事务结束才释放。
那请教哈 比如 不是UPDATE 是select 或insert ,执行的时候是不是也是一个事务,在执行的SQL语句后面加上WITH (HOLDLOCK) 是不是在这个过程中其他人是访问不了该表中数据的?? [/quote]只要是在事务中就可以了,没有必要加WITH (HOLDLOCK),事务的作用就是保证数据的一致性[/quote] 现在我在一个方法里 ,我向某个表要插入一条数据 其中有个字段 是自动读取到最大值 然后加一 比如 我现在要插入一条记录 这个时候我将会读取该数据表 得到某个字段的最大值 然后锁定该表 防止其他用户操作 然后进行插入命令 代码简单如下 string sql = "select max(cast(replace(serialno,'T','') as int)) from TuiHuoRuKu "; string serialno = DbHelperSQL.GetMax(sql) + 1).ToString() StringBuilder strSql = new StringBuilder(); string sql1="insert into TuiHuoRuKu Values(+’”serialno+“‘...................... 如何实现我读取到表最大值后就立刻锁定该表 防止其他用户操作
回复
misterliwei 2015-11-05
引用 6 楼 maocheng82 的回复:
[quote=引用 5 楼 misterliwei 的回复:] 首先没有使用BEGIN TRAN/ROLLBACK/COMMIT时,使用默认事务,一个UPDATE就是一个事务。 其次UPDATE会申请X锁,只有申请到该锁,才更新,并且X锁直到事务结束才释放。
那请教哈 比如 不是UPDATE 是select 或insert ,执行的时候是不是也是一个事务,在执行的SQL语句后面加上WITH (HOLDLOCK) 是不是在这个过程中其他人是访问不了该表中数据的?? [/quote] 是一个事务。 在READ COMMITTED隔离级别下,SELECT申请S锁,然后立即释放,如果使用WITH(HOLDLOCK),一般情况下,会到事务结束释放;INSERT申请X锁,直到事务结束释放,有无WITH(HOLDLOCK)都一样。 至于你说的别人访问不了,得看别人使用的隔离级别,及所做的操作(比如是SELECT还是UPDATE等等)。不同隔离级别下,这些操作所申请的锁是不同的。 别人是否可以访问,就看这些申请的锁和前面已经获得的锁是否相兼容。
回复
江南雪_158 2015-11-05
引用 6 楼 maocheng82 的回复:
[quote=引用 5 楼 misterliwei 的回复:] 首先没有使用BEGIN TRAN/ROLLBACK/COMMIT时,使用默认事务,一个UPDATE就是一个事务。 其次UPDATE会申请X锁,只有申请到该锁,才更新,并且X锁直到事务结束才释放。
那请教哈 比如 不是UPDATE 是select 或insert ,执行的时候是不是也是一个事务,在执行的SQL语句后面加上WITH (HOLDLOCK) 是不是在这个过程中其他人是访问不了该表中数据的?? [/quote]只要是在事务中就可以了,没有必要加WITH (HOLDLOCK),事务的作用就是保证数据的一致性
回复
misterliwei 2015-11-04
首先没有使用BEGIN TRAN/ROLLBACK/COMMIT时,使用默认事务,一个UPDATE就是一个事务。 其次UPDATE会申请X锁,只有申请到该锁,才更新,并且X锁直到事务结束才释放。
回复
maocheng82 2015-11-04
引用 3 楼 misterliwei 的回复:
加或者不加,都会变成800,不会变成600或500的。因为当遇到X锁锁定行时,等待对方结束就行了啊。
那我想问哈 比如我定义了一个方法,方法里没有用到事务 , 比如定义方法是 ..... string strsql = "update tb set sl=sl+入库数量 from tb where partno=物料号 " cmd.CommandText = strsql; return (int)cmd.ExecuteScalar(); 如果有用户在执行该方法实 是不是默认就是X锁
回复
misterliwei 2015-11-04
加或者不加,都会变成800,不会变成600或500的。因为当遇到X锁锁定行时,等待对方结束就行了啊。
回复
maocheng82 2015-11-04
引用 1 楼 misterliwei 的回复:
WITH (HOLDLOCK)根据名字应该是锁持续至事务结束,UPDATE使用的X锁一直到事务结束,所以没有必要加WITH(HOLDLOCK)。 再说,两个人分别加了200、300,,最后结果不就是800吗?为什么说是600或500?
我的意思是假设后面不加WITH (HOLDLOCK) 那数据有可能变成600或800了
回复
加载更多回复
相关推荐
发帖
疑难问题
创建于2007-09-28

2.1w+

社区成员

MS-SQL Server 疑难问题
申请成为版主
帖子事件
创建了帖子
2015-11-04 05:25
社区公告
暂无公告