首页 新闻 会员 周边

linq to sql 如何生成连续不重复的序列号

0
悬赏园豆:100 [已解决问题] 解决于 2014-09-01 13:38

我之前在论坛问别人“ 如何生成连续不重复的序列号 ”得到的方法如下:

建一个表,用一个字段储存最后一次生成的序号, 每次获取新序列号时开始一个新事务,更新序列号+1,然后select出来作为新序号用。因为每次都有事务,并且是先更新再查询,可以保证不会有重复数字生成。

请问在linq to sql中如何才能做到“一个事务中先更新后查询啊?因为我看到linq to sq在l更新、增加、删除记录前都要先使用from语句查询,这样的话怎样先更新后查询。求指点,求代码

问题补充:

继续等待中!关闭

feng12345123的主页 feng12345123 | 初学一级 | 园豆:26
提问于:2014-08-28 21:53
< >
分享
最佳答案
0

更新放在事务里面我懂,查询放在事务里面真心不懂。没听说过,今天第一次见识了。

“建一个表,用一个字段储存最后一次生成的序号, 每次获取新序列号时开始一个新事务,更新序列号+1,然后select出来作为新序号用。因为每次都有事务,并且是先更新再查询,可以保证不会有重复数字生成。”

这句话不知道是哪位大侠说的,反正我不敢苟同。

假设原始值ID为10,事务A,事务B执行如下

A: Update ID=ID+1

                                                 B: Update ID=ID+1

A: Select ID (这时候ID=12)

                 B: Select ID (ID=12)

如上证明,两个客户端得到了ID=12的序号。

 

补充:

不好意思,查了一下资料,没用过这么高级的属性。使用事务的最高级别确实可以做到。

TRANSACTION_SERIALIZABLE  可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的效率。附好园里相关文章,

脏读、不可重复读 共享锁、悲观锁 和 事务五种隔离级别

 

没有找到降低效率的详细资料,有知道的大神帮忙扫盲一下。

收获园豆:50
爱编程的大叔 | 高人七级 |园豆:30839 | 2014-08-28 22:07

继续回答楼主的问题,如果你可以接受最高级别的事务带来的效率损失的话。

后面的就简单了,跟LINQ真没有多大的关系了。

linq to sql 是支持SQL SERVER的存储过程的,

你可以这么写的

var myid=datacontext.pr_getid()

注:pr_getid为存储过程,返回ID值,在存储过程里面你可以写事务的。

爱编程的大叔 | 园豆:30839 (高人七级) | 2014-08-28 22:47

请教一下:

1、如果使用事务的最高级别确实可以做到,那么当你有这个需求时你会这样做吗?效率底是低成怎样?什么样的规模才适用最高级别的隔离?

2、是否有更科学的办法?

feng12345123 | 园豆:26 (初学一级) | 2014-08-29 14:50

@feng12345123: 说下我目前采用的方式吧,

也是一个数据表,保存一个数值,每次+1这样。

没有任何其他处理了(实际上就是当并发不存在....)

在没有发现因此造成的单据号重复之前,也没有打算在这上面花更多的成本去处理。

你可能觉得不好,不过这个真得看环境。

比如INTEL的CPU浮点计算问题,那是科学家算到小数点后N位才出现的,INTEL为此花了5亿还是多少?

如果你觉得你是INTEL这个级别的,那就要去研究,如果你是某个小计算器厂商,每年营业额是1千万,那就算了。

爱编程的大叔 | 园豆:30839 (高人七级) | 2014-08-29 15:20

@爱编程的大叔: 我想问一下,假如我启动一个事务(TRANSACTION_SERIALIZABLE 级别)当事务中的语句还没执行完毕电脑就断电了,那么据我所知道的,事务中所做的操作应该会回滚,但是事务对数据上锁的操作会取消吗?

feng12345123 | 园豆:26 (初学一级) | 2014-08-30 11:04

@feng12345123: 这个你可以试验的。首先存储过程中间可以暂停个几秒。

然后你可以有足够的时间把电脑的电源线拔掉。

这类的测评和研究其实真的很花时间和钱,所以我一向很尊敬有机会搞这些的人。

我的客户不会给我100万只为了搞这个的。所以我只知道理论知识。

 

我是典型的实用主义者。你看看罗质祥的视频其实你会发现,

要生存,还是要有实用主义精神的,比如你说屏幕这是,啥JDI的

你买的的最好的屏幕,假设价格500这样吧,你跟厂家说,我虽然只买10万个屏幕,

但是我每个屏幕给你5万,厂家保证屁颠屁颠的保证你的屏幕全面超越苹果的质素。

问题是你这钱从哪儿来?所以再怎么的追求美感,一旦要进入市场,

你一定只能有一些BUG,厂家做的无非是控制谁的BUG少,不影响使用而已。

 

利益相关,我做过外贸,研究过工厂成本。知道一点DELL和IBM的QA就怎么干活的。

只有研究所的,才可能不管工业成本。因为只是研究。

爱编程的大叔 | 园豆:30839 (高人七级) | 2014-08-30 11:10
其他回答(5)
0

你要的就是 :“ 如何生成连续不重复的序列号 ”

不要用Linq to sql 从数据库获取,然后处理,再导入 的方法,太烂了,而且效率很低,每生成一个序列号还要在网路走一大圈。

教你一个好方法,让数据库自动生成序列号。建一张保存序列号的根表A,另建一张表B(或者是使用系统表)B中保存两个值,一个值是当前使用到的序列号B_cur,另一个值是序列号跟表的最大序列号B_max。数据库建一个触发器,每当最大序列号和当前序列号间隔差小于1000(这个可以自定义)让触发器自动在序列号跟表里补新的序列号10000个(根据最大序列号向上补),先修改B_max = B_max + 10000 , 然后循环补跟表A。建一个存储过程 返回当前序列号B_cur(如果序列号不需要返回其他值,直接返回B_cur,减少对A的索引操作),然后修改B_cur = B_cur + 1

 

这种自动生成序列号的方法还是很效率的。(如果你只是要序列号,A表可以不用建立,直接建立B表,里面保留两项值,开始值和当前值)

牧师/preacher | 园豆:500 (菜鸟二级) | 2014-08-28 23:00
0

该用sql就用sql,linq只是一种查询方式,并不能满足所有业务需求,想用他来实现所有业务需求也是不现实的,

在sql上 update 字段+1  output 新值,这个语句每次执行都会有连续的值

收获园豆:20
吴瑞祥 | 园豆:29449 (高人七级) | 2014-08-29 08:44
0

LINQ如果你不先获得序号值,怎么更新

LINQ不能直接这样 UPDATE TABLE SET INDEX=INDEX+1

Yu | 园豆:12980 (专家六级) | 2014-08-29 08:49
0

根据你新表存储编号的方案,直接如下操作即可:

直接把上下文放在using中。然后

1、查编号(编号表),2、编号+1(写业务数据),3、编号+1(编号表)

整个提交,L2S中,每次提交都是一次事务操作。

幻天芒 | 园豆:37175 (高人七级) | 2014-08-29 10:01

就差你的代码,谢谢!

支持(0) 反对(0) feng12345123 | 园豆:26 (初学一级) | 2014-08-29 11:41

这个问题我研究过的,这样的操作没有办法防止重复。

客户A        查ID=10,因此编号应该是11

客户B   查ID=10,因此编号也应该是11,

这时候他们两个的数据都还没有写入数据库。

甚至可能还有客户C,查到也是10。

网络上一并发考虑,事情就多了。

 

因为通常业务表里面的这个单据号不会在数据库中设计为唯一性。

但是客户的业务又需要唯一性的单据号,所以事务是可能成功的,但是就出现了两个或是三个同样的单据号。

当然,如果你把业务单据号弄成数据表唯一性的设计,就可以通过事务这样来处理了。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-08-29 12:30

@feng12345123: 求方案

支持(0) 反对(0) feng12345123 | 园豆:26 (初学一级) | 2014-08-29 12:46

@爱编程的大叔: 对,我那种在高并发下确实不行,请考虑如下方案:可以在编号表增加时间戳字段,再执行编号表update的时候,加上这个where条件,如果受影响的行数为0,则回滚当前事务(需要开一个显式事务),并重新来一(N)次。

支持(0) 反对(0) 幻天芒 | 园豆:37175 (高人七级) | 2014-08-29 13:32
0

用触发器是解决这个问题的一个方案:

 

create trigger xxx on insert

as

begin

    declare @id int;

    select @id = id from inserted;

    update table set MyId = isnull((select top 1 MyId+1 from table where id<> @id  order by MyId), 1) where id=@id

end

 

这里,不使用id做连续号(可能意外),而使用MyId做连续号,默认值可以为0,但是,要再次查询才能获得这个值,性能稍有不如。

收获园豆:30
519740105 | 园豆:5810 (大侠五级) | 2014-08-31 14:20
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册