数据库并发问题,CSDN无大神?求助个问题,流程如下事务开始:查询一最大值(数字)插入一条数据,同一字段值设置
数据库并发问题,CSDN无大神? 求助个问题,流程如下 事务开始: 查询一最大值(数字) 插入一条数据,同一字段值设置为(第一步最大值 + 1) 提交事务 _____________________________ 这会有个线程同步问题,比如线程1,2同时查到最大值为10,则可能同时 INSERT 11 而我不能把字段配置成“unique", 因为业务的原因 求助诸位,先谢谢 C语言我知道可以弄LOCK锁函数,但是我想以数据库的方式,不知道有没有解决办法。比如,有没有办法让事务一开始,自动锁定,其他线程进入事务只能等待 如果描述不清,我还是举例算了,表有 产品和 版本两字段 产品,版本 —————————————————————— 产品A,1 产品A,2 产品XX,1 产品YY,1 产品YY,2 产品YY,3 如果两个事务同时查到产品A的最大版本2,则同时INSERT (产品A,3)明显就有问题。 (如果你想回答“弄成一个语句,类似insert into xxx values (select max ....)" 就算了,我不需要这样的答案) insert 数据库 SQL 同步 并发 [解决办法] 查完即update +1 即先update 再insert 用提交读。 如果可以降低并发性能可以应用更高的隔离级别,如可重复读。 个见。[解决办法] 我假定: ta id tb_name max_n 1 tb 23 2 tc 55 tb id .... 你从ta表中读取tb对应的max_n 然后插入记录到tb ,max_n +1 作为新记录的 id 那么 begin tran declare @id int update ta set max_n=max_n + 1 where tb_name = 'tb' select @id = max_n from ta if @error.... commit tran insert tb ... 如果插入不成功, 在这个进程下max_n +1 的结果(对tb表来说)将被丢弃, 从而行成断号。 如果你的表是这样的设计的话 ta表的记录是非常少的,那么update的操作速度将非常快, 在解决你所说的问题的同时并有效的提高并发量。[解决办法] 上面代码只是示意, 并没有严谨的写, 只表达意思。[解决办法] 我的习惯是,先select出最大值,再加1,再insert。为了防止重复,用主键或是唯一索引。这样,如果重复了,数据库会返回错误。[解决办法] 用事务的话,在当前事务没有提交的情况下,表不能做其他更新操作的吧.事务就是防止并发产生脏数据。所以产生你说的那个情况,不过相应的效率就降低了[解决办法]
引用: 引用:上面代码只是示意, 并没有严谨的写, 只表达意思。 update ta set max_n=max_n + 1 where tb_name = 'tb' 你这一句代码,就已经确保数据不会重复了。因为两个线程同时执行到这句时,一个事务没有提交,另一个是改不动的,会等待前一个事务提交后,才能执行。 但是我并不需要这样的答…… 呵呵, 最后一句肯定是看到了的。
本质的区别很大的。
不想重复,又不想等待(哪怕是理论上微秒纳秒级的), 你的要求无解。
[解决办法] 1, 既然你自己都说了,另一个进程失败了, 那何谈并发。
2,不要用max
[解决办法] 我觉得insert into xx(..., Num) values (..., select max(..))这个方案就不错
不过多并发环境的话可能效率就低了点
[解决办法] 流程如下修改就可以了
事务开始:
查询一最大值(数字),同时加排它锁
插入一条数据,同一字段值设置为(第一步最大值 + 1)
提交事务
[解决办法] 引用: 引用: 上面代码只是示意, 并没有严谨的写, 只表达意思。 update ta set max_n=max_n + 1 where tb_name = 'tb' 你这一句代码,就已经确保数据不会重复了。因为两个线程同时执行到这句时,一个事务没有提交,另一个是改不动的,会等待前一个事务提交后,才能执行。 但是我并不需要这样的答案,因为你没注意我问题……
要想不重复必然需要加锁,也就是牺牲效率,我想,不重复是功能需求,效率是性能需求,性能需要首先服从功能。
合并成一个语句并不能保证不重复(你的并发足够的情况下会出现重复)
自己加版本更不可行,自己写的效率不如内部的锁机制效率
遇到数据已经加锁只是等待,超时才会报错,大部分情况下并不引起失败,总比直接引起失败的方案好
[解决办法] 很简单啊,
你自己不都已经说了嘛,如果是C的话,你会用LOCK来控制,T-SQL当然也可以啊,
1,模拟C,自己建个全局临时表##TABLE2 ,或者用户表 ,专门用来做LOCK的锁定对象,
相当于LOCK(##TABLE2 ){}
2,通过一下方式就可以了,
Begin tran
select count(*) from ##TABLE2 (XLOCK )
DECLARE @I INT
Select @I=count(*)+1 from TABLEXXX
INSERT INTO . VALUES (@I)
Commit tran
[解决办法] 整个中国、世界、宇宙也没大神。。无神论者言
[解决办法] 方法一:把产品名和版本号合起来作为主键(不知道你为什么不愿意这样做),其中一个Insert必定出错,提醒用户重做或者自动重做加1。
方法二:乐观锁定(一般与你这个过程正好相反,你这个太例外了,这时不能设置这两个字段为主键)
(1)增加一列,加上为t,数据类型为timestamp,就是时间戳,它会自动填写,不用你管,Insert或Update时它都会自动更新,也不用你管。
(2)Insert版本号为-1的
(3)Select @t=t From XXTable Where 产品名=A and 版本号=-1
这句就是取时间戳的值,即使插入了n条版本号为-1的也无所谓,取第一条就可以了。
(4)Update XXTable Set 版本号=3 where 产品名=A and 版本号=-1 and t=@t
这时已经完成了,如果要知道哪个用户执行的失败了,查最后一条更新语句影响的行数即可,为0的就是失败的那个用户。
[解决办法] 根本不是一个级别的东西,有什么可比的。
对于你这个问题
如果数据库在并发上的处理属于具体问题的话, 那么框架在这里就是相对宏观的。
[解决办法] select max(a)+1 from b
[解决办法] 交给sql会自动处理
[解决办法] 1. 如果多个会话调用的是同一段语句的话,可以在select时加个updlock,这样就不会同时select到了
事务开始:
--查询一最大值(数字)
select max(ID) from table_name with(updlock)
插入一条数据,同一字段值设置为(第一步最大值 + 1)
提交事务
2. 如果select来自不同的语句,那可以按上面的写法,update的同时取值,并且+1
[解决办法] 都是高手啊 何必呢 一个事物就可以了 如果担心事物尽量短点的话 并发的几率不会太高 而且也不可能出现错误的 或者直接锁住哪一行也行啊
[解决办法] select * from xxx for update,这个是上锁的;
[解决办法] 观摩大神解决方案
[解决办法] [解决办法] 引用: 引用: 引用: 引用: 上面代码只是示意, 并没有严谨的写, 只表达意思。 update ta set max_n=max_n + 1 where tb_name = 'tb' 你这一句代码,就已经确保数据不会重复了。因为两个线程同时执行到这句时,一个事务没有提交,另一个是改不动的,…… 参照最后一句,“遇到数据已经加锁只是等待,超时才会报错,大部分情况下并不引起失败,总比直接引起失败的方案好 ”
自己增加版本或者使用时间戳,都会引起同时读取的另一线程的重新查询、重新插入,那样第一次查询就是浪费的了,总体效率在高并发情况下就是大问题
解决问题的方案不应该是越复杂越好
------解决方案--------------------
怕并发就上 设置隔离级别为串行化吧- -
一般不会有问题。
若你实在怕存在问题,就把所有插入做成SP 。都调用SP进行插入动作,在SP里做try catch + while。插入发生错误做重试,重试超过次数再条出报错就行了啊。
[解决办法] 应该根据实际的并发数和服务器能力做出对应的解决办法吧。
--mark
[解决办法] [解决办法] 事务的特性:原子性(Atomicity), 一致性(Consistency), 隔离性(Isolation), 持久性(Durability).这些特性简称ACID 一致性和隔离性 就会保证lz说的情况不存在,你用脏数据计算后提交数据库会报错回滚事务。 当然,这个也取决与事务的级别。 lz如果有疑问可以去找些资料好好看看。 [解决办法] 你这个明显是 transaction isolation的问题 用repeatable read或者serializable 4个transaction isolation level是ANSI/ISO标准制定的,和vendor无关。SQL Server默认是用locking来实现,Oracle则是row versioning。不管哪个都解决问题。 还有,SQL Sever也有Sequence object,不过需要2012版。 [解决办法]
把以上大神的方法整理一下,回头我也做个12306去卖票。 说来说去,不就是说的事务吗。事务有好几个级别,非要有需要把数据库级别设置高些。相应的效率会降低。