+ -
当前位置:首页 → 问答吧 → 多条select查询语句 为保一致性 加事务有用吗

多条select查询语句 为保一致性 加事务有用吗

时间:2011-12-08

来源:互联网

问题1
事务嘛 就是保持数据的一致性  
一般都是用在插入更新删除上 我不太清楚在查询上是否有用
请教下大家 
当然不光光全是查询 比如取最大值然后插入 这个时候是不是应该在 查询(select)最大值和插入这个最大值(insert)加入事务呢?

问题2
最后想问下 比如程序中一个取值sql语句开启一个事务 还没有释放的时候 假如又有人来取值 应该是会等待事务释放才能取是吧, 我就想问 这个事务它是怎么知道我要等的就是这个取值sql 就是说怎么知道我上一次的事务没释放呢??

作者: chopper7278   发布时间: 2011-12-08

SQL code

----原子性测试---

--表t1,id只能等于1
create table t1
(id int constraint chk_id check(id=1)
)
--表t2
create table t2
(id int 
)

--测试数据
insert into t2 values(1)
insert into t2 values(2)
insert into t2 values(3)
insert into t2 values(4)
insert into t2 values(5)


--情况1
insert into t1 select id from t2

--结果:表中没有插入记录
--说明:虽然t2表中包含1,但是sql server将insert语句作为一个逻辑单元,由于原子性,所以未插入记录


--情况2 transaction
begin tran

    insert into t1 select id from t2
    insert into t1 values(1)
    
commit

--结果:t1中插入一条记录
--说明:单独的begin tran,commit不具有原子性

--情况3
set XACT_ABORT on
begin tran

    insert into t1 select id from t2
    insert into t1 values(1)
    
commit

--结果:表中没有插入记录
--说明:set XACT_ABORT 在语句失败时自动回滚(之前的如果正确还是执行,见情况4)



--情况4 try catch
begin try
    begin tran
    insert into t1 values(1)
    insert into t1 select id from t2
    insert into t1 values(1)
    commit
end try
begin catch
  rollback
   print 'error'
  return
end catch

--结果:表中没有插入记录
--说明: try catch 使语句具有原子性



作者: koumingjie   发布时间: 2011-12-08

当然不光光全是查询 比如取最大值然后插入 这个时候是不是应该在 查询(select)最大值和插入这个最大值(insert)加入事务呢?


针对这个问题,我的解决办法是单独建立一个最大值管理表,每次需要用最大值时,先将最大值+1,再取出来

作者: koumingjie   发布时间: 2011-12-08

#1.确认自己的隔离级别
#2.在不同的隔离级别上,加的锁是不一样的
#3.事务只是为了保证完整性.在一个事务中,select行锁查询完就会释放,而排他锁会保持到事务结束
所以
问题1: 如果是多线程,即使在查询(select)最大值和插入这个最大值(insert)加入事务,也保证不了插入最大值的正确性.
问题2: 事务未结束前,另一个进程访问相同的数据,如果访问时没有锁冲突,就可以访问,否则等待.是否产生锁冲突决定于锁的类型,请注意上面讲的#3,就可以解答你的问题.
问题3: 参考问题1.你现在的解决的办法是对的.因为最大值管理表中的维护最大值是一行记录,你在更新这行记录时,会使这行记录拥有一个更新锁(最终会成为排他锁),保证了多进程访问时的正确性.
关于事务和锁的更多资料,请自己再学习一下,搞清楚它们之间的关系.

作者: wwwwgou   发布时间: 2011-12-08

一个事务中只有多条select语句,由于默认的隔离级别下,select查询只会获得行共享锁,所以加事务是多余的;这时的一致性取决于SQL SERVER的隔离级别.
#1.隔离级别
#2.锁
#3.事务
需要一一了解,才能贯通.

作者: wwwwgou   发布时间: 2011-12-08

引用 1 楼 koumingjie 的回复:
SQL code


----原子性测试---

--表t1,id只能等于1
create table t1
(id int constraint chk_id check(id=1)
)
--表t2
create table t2
(id int
)

--测试数据
insert into t2 values(1)
insert into t2 values(2……

对于第一种情况,请使用@@error判断sql的执行结果。

作者: lang8134   发布时间: 2011-12-08

事务起到保持一致性作用的是事务中使用了锁,所以不在于用什么语句,而在于是否有锁
比如事务中使用SELECT ... FROM ... WITH (XLOCK,HOLDLOCK) ...
这样的语句,就会锁定一定的记录不允许其他进程读写,INSERT,UPDATE一般会自动加锁。

两个问题好像是一个问题,就上面的回答了

作者: Haiwer   发布时间: 2011-12-08

引用 4 楼 wwwwgou 的回复:

一个事务中只有多条select语句,由于默认的隔离级别下,select查询只会获得行共享锁,所以加事务是多余的;这时的一致性取决于SQL SERVER的隔离级别.
#1.隔离级别
#2.锁
#3.事务
需要一一了解,才能贯通.

我是在程序里加的事务
SqlTransaction transaction = connection.BeginTransaction();
这样加如果是多条select语句是不是也是行共享锁

作者: chopper7278   发布时间: 2011-12-08

概念先理解,再代码,否则就算代码对了也没解决实际问题,稍有修改就会不知所措

作者: Haiwer   发布时间: 2011-12-08

引用 7 楼 chopper7278 的回复:
引用 4 楼 wwwwgou 的回复:

一个事务中只有多条select语句,由于默认的隔离级别下,select查询只会获得行共享锁,所以加事务是多余的;这时的一致性取决于SQL SERVER的隔离级别.
#1.隔离级别
#2.锁
#3.事务
需要一一了解,才能贯通.

我是在程序里加的事务
SqlTransaction transaction = connection.Begi……


是的

作者: fredrickhu   发布时间: 2011-12-08

SELECT 会自动加共享锁。

作者: fredrickhu   发布时间: 2011-12-08

引用 9 楼 fredrickhu 的回复:
是的

那怎么弄呢 一般大家是怎么做的呢 就是取最大值然后插入 或者是多条查询的时候

作者: chopper7278   发布时间: 2011-12-08

引用 7 楼 chopper7278 的回复:
我是在程序里加的事务
SqlTransaction transaction = connection.BeginTransaction();
这样加如果是多条select语句是不是也是行共享锁

默认隔离级别下,是的.

作者: wwwwgou   发布时间: 2011-12-08

+1
引用 8 楼 haiwer 的回复:
概念先理解,再代码,否则就算代码对了也没解决实际问题,稍有修改就会不知所措

作者: q465897859   发布时间: 2011-12-08

引用 13 楼 q465897859 的回复:

+1引用 8 楼 haiwer 的回复:
概念先理解,再代码,否则就算代码对了也没解决实际问题,稍有修改就会不知所措


我哭了///

作者: xiaolinyouni   发布时间: 2011-12-08

我也有类似的问题,在一个存储过程中先用select查询库存,如果满足条件就update修改库存,
如果select默认是共享锁,那两个工作站同时select库存表,都认为库存足够,而执行下面的update语句,岂不是会造成数据错误。
怎样给select语句加排他锁
是这样吗:SELECT ... FROM ... WITH (XLOCK,HOLDLOCK)

作者: oracle185   发布时间: 2011-12-08

1#说得很对,所以,要想真正达到事务的效果,必须使用下列方式才能达到要么全部成功,要么全部失败!

begin try
  begin tran
  insert into t1 values(1)
  insert into t1 select id from t2
  insert into t1 values(1)
  commit
end try
begin catch
  rollback
  print 'error'
  return
end catch

作者: tyxddgs   发布时间: 2011-12-08

引用 4 楼 wwwwgou 的回复:
一个事务中只有多条select语句,由于默认的隔离级别下,select查询只会获得行共享锁,所以加事务是多余的;这时的一致性取决于SQL SERVER的隔离级别.
#1.隔离级别
#2.锁
#3.事务
需要一一了解,才能贯通.

老师,在存储过程中怎样使用隔离级别和锁

作者: oracle185   发布时间: 2011-12-08