Foxtable(狐表)用户栏目专家坐堂 → [分享]<结贴>异步不能用狐表自带的事务,使用OleDb原生事务,解决异步comit线程干扰报错:如果分配给命令的连接位于本地挂起事务中,ExecuteNonQuery 要求命令拥有事务。命令的 Transaction 属性尚未初始化。


  共有5178人关注过本帖树形打印复制链接

主题:[分享]<结贴>异步不能用狐表自带的事务,使用OleDb原生事务,解决异步comit线程干扰报错:如果分配给命令的连接位于本地挂起事务中,ExecuteNonQuery 要求命令拥有事务。命令的 Transaction 属性尚未初始化。

帅哥哟,离线,有人找我吗?
chen37280600
  1楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:六尾狐 帖子:1279 积分:7959 威望:0 精华:4 注册:2017/12/31 14:53:00
[分享]异步不能用狐表自带的事务,使用OleDb原生事务,解决异步comit线程干扰报错:如果分配给命令的连接位于本地挂起事务中,ExecuteNonQuery 要求命令拥有事务。命令的 Transaction 属性尚未初始化。  发帖心情 Post By:2020/5/5 22:52:00 [显示全部帖子]

狐表在20210529后的版本已增加可以异步使用的Sql事务,这个帖子的方法不再需要了。但是可以留作研究OleDb独立事务

=============================================
我的bs里,有些方法有事务,一般用于入库单和出库单,涉及到多表的批量插入,因此按照官方文档,开了事务。这些事务,由于要插入的行和修改的表都比较多,耗时较长,都启动了异步。

于是今天出现一个:
2020-05-05 10:45:54.7266
报错定位:
如果分配给命令的连接位于本地挂起事务中,ExecuteNonQuery 要求命令拥有事务。命令的 Transaction 属性尚未初始化。
   在 System.Data.OleDb.OleDbConnectionInternal.ValidateTransaction(OleDbTransaction transaction, String method)
   在 System.Data.OleDb.OleDbConnection.ValidateTransaction(OleDbTransaction transaction, String method)
   在 System.Data.OleDb.OleDbCommand.ValidateConnectionAndTransaction(String method)
   在 System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
   在 System.Data.OleDb.OleDbCommand.ExecuteNonQuery()
   在 System.Data.Common.DbDataAdapter.UpdateRowExecute(RowUpdatedEventArgs rowUpdatedEvent, IDbCommand dataCommand, StatementType cmdIndex)
   在 System.Data.Common.DbDataAdapter.Update(DataRow[] dataRows, DataTableMapping tableMapping)


按照事务的代码:
Try
    Connections("数据源").BeginTransaction()
'开始事务
    Dim cmd As new
SQLCommand
    cmd.ConnectionName =
"数据源"
    cmd.CommandText =
"Del ete From {订单} Where [订单编号] = 32"
    cmd.
ExecuteNonQuery
    cmd.CommandText =
"Del ete From {订单明细} Where [订单编号] = 32"
    cmd.
ExecuteNonQuery
    Connections("数据源").Commit
'提交事务,所有操作生效

Catch
ex As Exception '如果出错
    Connections("数据源").Rollback()
'回滚事务,撤销所有操作

End
Try

我在感觉,异步多线程下,Connections("数据源")是存在线程干扰,这个东西并不是new出来的,而且在狐表启动后,外部数据源里初始化好的。多个线程共用一个Connections("数据源"),

场景1:
A线程把事务Begin,
B线程刚好到把事务Commit
A线程才开始插入数据,于是就报错了

场景2:
A线程把事务Begin,
A线程对事务配置了待执行的插入代码
B线程刚好到把事务Commit,由B来帮A线程Commit
A线程继续对事务配置剩下待执行的插入代码,已经出问题了

我个人感觉会有问题,这个问题貌似需要狐爸的资深用户解答


我去百度了一个mysql里事务和多线程,貌似跟我说的一样

那BS里怎么解决耗时较久的写入问题?

[此贴子已经被作者于2022/1/14 10:44:09编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chen37280600
  2楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:六尾狐 帖子:1279 积分:7959 威望:0 精华:4 注册:2017/12/31 14:53:00
  发帖心情 Post By:2020/5/6 9:18:00 [显示全部帖子]

Connection Pool?

 回到顶部
帅哥哟,离线,有人找我吗?
chen37280600
  3楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:六尾狐 帖子:1279 积分:7959 威望:0 精华:4 注册:2017/12/31 14:53:00
  发帖心情 Post By:2020/5/6 9:43:00 [显示全部帖子]

那能不能利用狐表的Connections,动态创建连接,用创建出来的连接用于异步里的事务。用完后,我自己回收控制资源,自己搞数据库连接池


它创建一个正在使用的数据库池集合,空闲的数据库池集合

1请求数据库连接时
2先在空闲里找。如果有,就给予;如果没有,就创建一个新的数据库连接池。把该连接放到正在使用的池
3用完后把数据库连接放回到空闲池,等待下次使用。

以上思路,用狐表设计并不能难做。
只是别人还有个超时自动关闭闲置的数据库连接

----------------------------------
创建线程池,是因为避免创建和销毁时的耗时,但是对于已经在异步里的线程,其实是否耗时,都没所谓,已经不堵塞主线程。
根据资料,一般创建和销毁数据库连接池要250ms,执行单条sql是170ms。对于用户保存入库单,多表插入上条sql,数据库连接的创建与销毁时间,并不是什么紧缺的资源

而且我的系统,一般多就几十人一起用,能审核的就有3-5个人。感觉不需要上线程池,狐爸有什么建议吗?

(其实我目前只想单纯解决这个报错,让事务能在异步顺利执行。系统用户数也就不到10个人,一天总共插入3000条数据左右而已)
[此贴子已经被作者于2020/5/6 9:56:07编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chen37280600
  4楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:六尾狐 帖子:1279 积分:7959 威望:0 精华:4 注册:2017/12/31 14:53:00
  发帖心情 Post By:2020/5/6 9:59:00 [显示全部帖子]

我看了ado.net的SqlConnection     https://blog.csdn.net/winfredzen/article/details/72898152

它的SqlConnection,与狐表的Connection是同一个玩意吗?狐表有引入好这个dll,能直接用吗?能支持参数化吗?

 回到顶部
帅哥哟,离线,有人找我吗?
chen37280600
  5楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:六尾狐 帖子:1279 积分:7959 威望:0 精华:4 注册:2017/12/31 14:53:00
  发帖心情 Post By:2020/5/6 11:54:00 [显示全部帖子]

总结了一段这样的事务代码,用OleDb,在异步里没问题
大家用就是了

Dim foxCon As Connection = Connections("DB") '狐表本地的数据库源
Dim oleCon As new System.Data.OleDb.OleDbConnection() '创建新的OleDB连接对象
oleCon.ConnectionString = foxCon.ConnectionString '设置连接字符串
Dim trans As System.Data.OleDb.OleDbTransaction '创建一个事务对象准备,注意不能new,因为是Null
Dim oleCmd As new System.Data.OleDb.OleDbCommand '创建一个SQL执行器
oleCmd.Connection = oleCon '把Sql执行器与数据库连接绑定

Try
    oleCon.Open() '启动数据库连接
    trans = oleCon.BeginTransaction() '启动事务,并返回这个事务对象    
    oleCmd.Transaction = trans '把SQL执行器与事务绑定

    '业务代码---
    oleCmd.CommandText = "Insert Into workinfo (ID,Name) Values(?,?)"
    oleCmd.Parameters.Clear '非常重要
    oleCmd.Parameters.Add("@ID","111")
    oleCmd.Parameters.Add("@Name","Test1")
    oleCmd.ExecuteNonQuery
    oleCmd.CommandText = "Insert Into workinfo (ID,Name2) Values(?,?)"
    oleCmd.Parameters.Clear '非常重要
    oleCmd.Parameters.Add("@ID","222")
    oleCmd.Parameters.Add("@Name","Test2")
    oleCmd.ExecuteNonQuery
    '业务代码---
    trans.Commit() '提交事务
Catch ex As Exception '如果出错
    trans.Rollback() '回滚事务,撤销所有操作
    MessageBox.show(ex.ToString())
Finally
    oleCon.Close()
End Try


### 注意空值的赋值方法!
1. 在狐表封装的sqlCommand里,oleCmd.Parameters.Add("@ApproveTime",Nothing)
2. 在原生的OleDb里,oleCmd.Parameters.Add("@ApproveTime",DBNull.Value)


[此贴子已经被作者于2020/5/6 22:14:24编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chen37280600
  6楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:六尾狐 帖子:1279 积分:7959 威望:0 精华:4 注册:2017/12/31 14:53:00
  发帖心情 Post By:2020/5/6 15:09:00 [显示全部帖子]

已总结解决,见7楼

 回到顶部