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) 研究的不是很深刻 望大家指教
...全文
267 21 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
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了
加载更多回复(1)

22,301

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧