解决多线程调用sql存储过程问题

  • 场景:

我们程序现在改成多线程了,我现在需要把临时表中的数据给插入到TABLE_M中,但这时候可能其他的线程也在插入,我就不能用之前我们的方案了(select max(oid) from Tuning.TABLE_M。。。,之后去维护主子表关系,改掉TABLE_M的OID的自增属性,插入,之后再添加上自增属性。。。。。。)

我现在是想这样操作:

1,)先插入把临时数据插入到TABLE_M(OID是自增的)中(Insert Into ….select …),我之后获取 select Scope_Identity() as @MaxTABLE_MOID,之后根据这个@MaxTABLE_MOID去修改临时表中的TABLE_MOID.

1.1,)(1,)这种方案会不会出现以下问题:

A线程, 1-10 共10条记录,

B 线程,1-10 共10条记录

A线程插入的时候,

B线程也在再插入

A线程 与 B线程是交互的插入,A线程插入一条,B线程插入一条

运行起来像这样:

比如 此时TABLE_M的OID为 100

A线程插入第一条 TABLE_M的OID变为 101

B线程插入第一条 TABLE_M的OID变为 102

当我A线程插入完的时候,我A线程最后一条记录插入的OID为 120

这时候我的Temp 要到这个120 去修改字表关系

TABLE_M(OID=120) 是A 插入的没问题

TABLE_M(OID=119)是B插入的,这时却关联到了A线程对应的临时表的第9条记录

悲哀!!!

1.2,)我们是不是要在插入的时候使用With(lock)

2,)我还有一种想法,就是先插入完成后,根据条件查询出该批数据插入TABLE_M的生成的OID,之后这些OID去和temp匹配(按照顺序匹配,因为插入temp肯定是有序的插入),之后修改temp中的TABLE_MOID,这样就可以把子数据插入到TABLE_M_LteCell,TABLE_M_GsmCell,TABLE_M_TdsCell中。

  • DBA提供解决方案

我们可以单独做一个表来进行OID自增的维护,可以暂时称为MAX_OID表。最简单的方式是里面仅仅记录:当前最大的OID。

这样我们在做多线程操作的时候遵循以下步骤

1. 取得MAX_OID表中的值,这样就可以获得自增的起始序列号‍

2. 获得此次插入时候的临时表的最大行数。不要使用select count(1) from table,使用如下语句,可以获得最大的性能。

直接获取表行数sql语句:

select sum(row_count)

from sys.dm_db_partition_stats

where index_id<1 and object_id=object_id(‘表名‘)

3. 使用max_oid+临时表的表行数,可以得到将临时表插入到主表之后,主表未来最大的MAXOID号

4. 更新MAX_OID表。将表内数据改为:‍max_oid+临时表的表行数‍

特别注意:为了保证事务一致性,上述步骤需要在一个事务中完成,需要以下语句

SET XACT_ABORT ON

begin tran

执行的sql语句(即上面1-4的逻辑操作)

commit

以上四个步骤虽然文字上比较啰嗦,但是实际操作会非常快。使用的全是系统表来读取,肯定是在毫秒级别,不会影响性能。

这样,每个线程读取的都是MAX_OID表中的值,就不会产生冲突了。‍

如下面的例子:

目前MAX_OID 最大值为100.‍

线程一的临时表为30行

线程二的临时表为40行

线程一:

1.读取MAX_OID 表。得到100‍

2.获得临时表行数:30

3.得到预测的maxoid为100+30=130

4.将MAX_OID 更改为130.‍

线程二:

1.读取MAX_OID 表。得到130

2.获得临时表行数:40

3.得到预测的maxoid为130+40=170

4.将MAX_OID 更改为170.

注意:线程二得到的MAX_OID 一定是130,而不是100.因为线程一已经更新了这个值。且更新的过程中加锁。线程二是读取不到100这个数值的。‍

这样就可以避免冲突了。

时间: 2024-09-30 14:29:23

解决多线程调用sql存储过程问题的相关文章

Dynamics CRM - 使用 C# Plugin 调用 SQL 存储过程

有时候,在 Dynamics CRM Plugin 中通过 linq 查询数据会比较慢,可以通过采用在 C# plugin 中直接调用数据库存储过程的方式来提高效率,具体过程如下: 1.新建一个存储过程: ALTER PROCEDURE [dbo].[p_Sample] AS BEGIN SELECT COUNT(dbo.Table.Id) FROM dbo.Table WHERE dbo.Table.Name LIKE '张%' END 2.在 Plugin 中调用存储过程: string s

关于MVC工厂模式的增删改查sql存储过程

这里MVC中用到了反射,工厂,泛型,接口 在搭建框架的时候,除了MVC的三层以外,还有泛型的接口层和工厂层 下面是dal层调用sql存储过程,增删改查,dal层继承了接口层,实现了接口层里面的方法 1 namespace DAL 2 { 3 public class DalHouse : IHouse 4 { 5 public int Add(HouseInfo m) 6 { 7 string sql = "pro_add"; 8 SqlParameter eid = new SqlP

(转)jdbc 调用 sql server 的存储过程时“该语句没有返回结果集”的解决方法

本文转载自:http://hedyn.iteye.com/blog/856040 在JDBC中调用SQL Server中的存储过程时出现如下异常: com.microsoft.sqlserver.jdbc.SQLServerException: 该语句没有返回结果集. at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:171) at com.microsof

Cpp 调用sql server 存储过程时不返回output参数解决办法

Cpp 调用sql server 存储过程时不返回output参数,但是在ssms中调用的时候能正常返回,貌似数据库和应用代码是一切正常,再测试用c#调用也能正常获取output参数,在存储过程的的开始加上set nocount on,就能解决这个问题. 墙外原文件:点击打开链接

PHP多次调用Mysql存储过程报错解决办法

PHP多次调用Mysql数据库的存储过程会出现问题,主要问题为存储过程中执行多次SQL语句不能一一释放导致的,网上找了一些解决办法,比如使用 multi_query 然后一个一个释放,但是发现根本不适合我们的项目,我们使用CI框架写的,更多的是使用CI的数据库处理方法.所以只能另辟蹊径. 一次偶然,把Mysql链接方式改成了mysqli,两种不同的PHP连接mysql的扩展,官方在高版本中推荐使用mysqli,结果却奇迹般好了,使用Mysql长连接也行,天意么? PHP多次调用Mysql存储过程

SQL 语句调用这个存储过程,生成顺序编码

一直很讨厌存储过程,没想到今天帮了我大忙啊,或许会因为今天让我慢慢喜欢上存储过程吧,不多说了,切入正题 在使用数据库的时候,难免要在使用过程中进行删除的操作,如果是使用int类型的字段,令其自增长,这是个最简单的办法,但是后果会有些不是你想要的!看下这个Demo: 1.建立这样的简单的表Test. 2.设置字段id的自增. 3.表添加数据 insert into Test(name) values('TestName') insert into Test(name) values('TestNa

多线程调用生成主键流水号存储过程产生主键冲突问题解决方案

遇到开发多线程测试插入数据的时候发现主键冲突问题 问题具体描述如下: -------------------------------------------------------------- 调用Procedure_insert Procedure_insert Begin Call procedure(获取流水号) Insert into table values(流水号作为id,其他列); End 流水号存储过程: Update 统计表 统计字段+1 Update 统计表 最终流水号 s

c#客户端调用sql server 存储过程速度慢的问题

1 : c#代码是 SqlConnection connNew = null; connNew = new SqlConnection(@"Data Source="XXX"); connNew.Open(); SqlCommand commNew = connNew.CreateCommand(); commNew.CommandText = "sp_catcher_MeraRptCAV_Insert_detail"; commNew.CommandTy

qt调用sql server存储过程并获取output参数

最近新做的一个项目需要使用qt连接另一台机器上的sql server,虽然网上已有类似文章,但还是有些其中很少提及的问题,故在这里汇总下: qt连接sql server可以参考这篇文章,如果是连接另一台机器的sql server就不用执行第一步“开启ODBC驱动”了 http://www.cnblogs.com/shaolw/p/3411285.html 另外指定数据库用户名和密码可以使用Uid和Pwd,即原文dsn参数可以这样写: QString dsn = QString("Driver={