循环update+insert(事务),导致 死锁

chai1338 2016-05-12 09:34:16

foreach (DataRow dr in dt.Rows)
{
TransactionOptions option = new TransactionOptions();
//设置事务隔离级别
option.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, option))
{
try
{
UsersService.UpdateMember(u_guid, Promotion_lines, Promotion_lines2);
UsersService.InsertTiEHistory(u_guid, Promotion_lines, Promotion_lines2);
ts.Complete();
Logger.LOG_ERROR.Error("成功:" + u_phone);
SendMessage(u_phone);
}
catch (Exception ex)
{
Logger.LOG_ERROR.Error("失败:" + ex.Message);
}
finally
{
//释放资源
ts.Dispose();
}
}
}
insert语句
string sql = "INSERT INTO U_TiEHistory (u_guid,line1,line2,createdOn) VALUES (@u_guid,@line1,@line2,GETDATE())";


表结构
SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[U_TiEHistory](
[id] [int] IDENTITY(1,1) NOT NULL,
[u_guid] [varchar](40) NULL,
[line1] [decimal](18, 2) NULL,
[line2] [decimal](18, 2) NULL,
[createdOn] [datetime] NULL,
CONSTRAINT [PK_TiEHistory] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO



线上运行后查看日志发现insert死锁。insert的数据一开始一分钟插入很多条,逐渐减慢到1分钟插入一条
把数据库copy到本地运行正常没问题
...全文
1148 10 打赏 收藏 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
xdashewan 2016-05-12
  • 打赏
  • 举报
回复
你可以看一下这篇文章http://www.cnblogs.com/CareySon/archive/2012/09/19/2693555.html 文章里介绍了排查手段和产生死锁的一些情况,你可以对照你的设计看一下符合哪一项
chai1338 2016-05-12
  • 打赏
  • 举报
回复
引用 4 楼 xdashewan 的回复:
[quote=引用 2 楼 chai1338 的回复:] update操作的是另外一个表 insert的又是另外一个表
对,我说的情况就是“update操作的是另外一个表”的情况下[/quote] 我的这个项目就是一个简单的windows服务,定时update 表A,把记录 insert表B 但是表A有其他线上项目在运行,你的意思是其他项目有事务占据了表A?
chai1338 2016-05-12
  • 打赏
  • 举报
回复
引用 1 楼 xdashewan 的回复:
死锁往往不是单个语句造成,从你这里推测可能是有事务占据着U_TiEHistory资源想访问UpdateMember操作的表,而同时你的操作占据UpdateMember操作的表,想要访问U_TiEHistory,就会造成死锁,当然只是推测,具体情况你得自己分析
U_TiEHistory这个表整个项目只有这行代码有写入操作, 其他地方没有任何读写
xdashewan 2016-05-12
  • 打赏
  • 举报
回复
引用 2 楼 chai1338 的回复:
update操作的是另外一个表 insert的又是另外一个表
对,我说的情况就是“update操作的是另外一个表”的情况下
chai1338 2016-05-12
  • 打赏
  • 举报
回复
引用 1 楼 xdashewan 的回复:
死锁往往不是单个语句造成,从你这里推测可能是有事务占据着U_TiEHistory资源想访问UpdateMember操作的表,而同时你的操作占据UpdateMember操作的表,想要访问U_TiEHistory,就会造成死锁,当然只是推测,具体情况你得自己分析
update操作的是另外一个表 insert的又是另外一个表
xdashewan 2016-05-12
  • 打赏
  • 举报
回复
死锁往往不是单个语句造成,从你这里推测可能是有事务占据着U_TiEHistory资源想访问UpdateMember操作的表,而同时你的操作占据UpdateMember操作的表,想要访问U_TiEHistory,就会造成死锁,当然只是推测,具体情况你得自己分析
_小黑_ 2016-05-12
  • 打赏
  • 举报
回复
你应该循环执行SQL语句 判断 当前执行的sql 语句是否成功 如果失败 的话 回滚事物 之后退出循环 而不是 每保存一条数据 开启 一次事物 这样 当然容易 造成死锁
chai1338 2016-05-12
  • 打赏
  • 举报
回复
引用 7 楼 sp1234 的回复:
随便说2个不如意的代码: 1. 事务应该写到for循环之外,怎么放到里边呢?至少应该几百个操作之后才进行一次 commit,怎么能频繁地 commit 呢? 2. 无关的什么Log和SendMessage,应该尽量在子线程中去执行,不要占用你的操作时间。你的操作应该尽快结束,而不是拖延时间。
好的 非常好的建议 谢谢
  • 打赏
  • 举报
回复
最后,关系数据库的性能很低,如果是大批量处理,特别是先查询然后再修改的这种所谓记录方式,即使有索引也不会很快。此时应该考虑你的设计是不是有些滥用数据库了。 对于大批量转入数据的操作,考虑仅仅用 insert,而没有 update、delete 操作。并且就算是 insert操作,也不写有索引的表,或者先删除索引、插入数据之后才重建索引。 总之,不要用关系数据库做它并不适合做的事情。如果你要记录过度频繁的日志,或者使用 NoSql,或者使用内存数据库(它批量保存数据到磁盘,并不保证数据不丢失)。
  • 打赏
  • 举报
回复
随便说2个不如意的代码: 1. 事务应该写到for循环之外,怎么放到里边呢?至少应该几百个操作之后才进行一次 commit,怎么能频繁地 commit 呢? 2. 无关的什么Log和SendMessage,应该尽量在子线程中去执行,不要占用你的操作时间。你的操作应该尽快结束,而不是拖延时间。

111,128

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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