关于SEMQ修改的若干说明


1. 示例代码

int CSEMQ::Save(CSEMQItem &msg) {

       USE_CURSOR_DBC(pdbor,this->dbc_name_.c_str(),CLIENT_CURSOR);

       ITableHandler *th = CBasePluginModule::db_helper_->NewTableHandler(pdbor,this->st_name_.c_str());

       AUTO_POINTER_NODECLARE(ITableHandler,th);

       vector<CQQ_OBJECT_ID> &v_rec = semq_tss_->v_rec;

       pdbor->SetTXHook(TxHook,this); ///< 设置事务挂钩函数

       pdbor->BeginTrans();

       th->BindField("src_type",(char**)&src_type,sizeof(src_type));

       th->BindField("src_id",(char**)&src_id,sizeof(src_id));

       ......

       th->BindField("f007b_0031",buffer,buffer_len);

       if (th->Insert2()) {

              return -1;

       }

       unsigned __int64 object_id2;

       if (pdbor->GetDBExt()->GetLastID(object_id2,2)) {

              return -2;

       }

       v_rec.push_back(object_id2); ///< 把新增记录的 object_id 写入 TSS , 待事务结束后处理

 

       pdbor->CommitTrans();

 

       return 0;

}

 

2. 事务挂钩

利用 IDbAccessor2 SetTXHook 方法为连接对象设置事务挂钩函数 .

该函数在事务结束后 (Commit Rollback) 时调用 .

 

出于嵌套事务和程序模块性考虑 ,IDbAccessor2 支持嵌套事务 , 内部有事务嵌套计数器 .

CommitTrans 调用并不真正意味数据库事务的提交 .

这样就可能有外层事务的情况下 ,Insert2 的记录并没有真正提交,其它会话无法访问 .

事务钩子的作用就是在产生数据库提交事务动作时再执行 .

实际的事务钩子函数如下 :

 

struct SEMQ_TSS {

       vector<CQQ_OBJECT_ID> v_rec;

};

ACE_TSS<SEMQ_TSS> semq_tss_;

int TxHook(short status,void *mq) {

       if (status==0) {

              semq_tss_->v_rec.clear();

              return 0;

       }

       CSEMQ *semq = (CSEMQ*)mq;

       vector<CQQ_OBJECT_ID> &v = semq_tss_->v_rec;

       vector<CQQ_OBJECT_ID>::iterator iter = v.begin();

       while(iter!=v.end()) {

              semq->SendRecord(*iter); ///< 发送新增的记录

              iter++;

       }

       semq_tss_->v_rec.clear();

 

       return 0;

}

 

3.Insert2 GetLastID 失败的问题

ITableHandler Insert2 采用 ADO AddNew/PutCollect 方法实现 , 目的是支持大字段的操作

IDBExt GetLastID 目的是获取新 Insert 记录的自增字段的值 .(原始语义并不明确)

SQL Server 扩展实现 GetLastID 采用的是 SCOPE_IDENTITY().

 

Insert2 后获取 object_id 时失败 ,select SCOPE_IDENTITY() 返回 VT_NULL;

 

建立测试环境诊断此问题 :

2.1

CREATE TABLE [dbo].[test1](

       [f1] [int] IDENTITY(1,1) NOT NULL,

       [f2] [nchar](10) COLLATE Chinese_PRC_CI_AS NULL

) ON [PRIMARY]

 

2.2 测试代码

       USE_CURSOR_DBC(pdbor,"testdb",SERVER_CURSOR);

       string sql = "select * from test1 where 1<>1";

       AUTO_QUERY_RECORDSET(CRecordset,prs,pdbor);

       prs = pdbor->Query(sql.c_str(),adOpenStatic,adLockOptimistic);

       prs->AddNew();

       prs->PutCollect("f2","dddddd");

       prs->Update();

       unsigned __int64 object_id2;

       if (pdbor->GetDBExt()->GetLastID(object_id2)) {

              return -1;

       }

 

SQL Server Profiler 看出 ,Update 后执行的语句为 :

exec sp_executesql N'SET NOCOUNT OFF; INSERT INTO "test".."test1" ("f2") VALUES (@P1); SELECT SCOPE_IDENTITY() AS SCOPE_ID_COLUMN',N'@P1 nvarchar(10)',N'dddddd    '

可见作用域不同 (sp_executesql insert).

这符合 SCOPE_IDENTITY() 的说明 .

 

解决 :

       修改 GetLastID, 以支持不同语义的 identity. 通过 scope 指明范围 (1- 当前会话当前作用域 2- 当前会话 )

       virtual int GetLastID(unsigned __int64 &object_id,short scope=1) = 0; /// 获取最后插入记录的自增序列值

 调用GetLastID(object_id2,2);

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值