OLEDB事务
学过数据的人一般都知道事务的重要性,事务是一种对数据源的一系列更新进行分组或者批处理以便当所有更新都成功时同时提交更新,或者任意一个更新失败时进行回滚将数据库中的数据回滚到执行批处理中的所有操作之前的一种方法。使用事务保证了数据的完整性。这里不展开详细的说事务,只是谈谈OLEDB在事务上的支持
ITransactionLocal接口
OLEDB中支持事务的接口是ITransactionLocal接口,该接口是一个可选接口,OLEDB并不强制要求所有数据库都支持该接口,所以在使用之前需要先判断是否支持,好在现在常见的几种数据库都支持。
- 该接口属于回话对象,因此要得到该接口只需要根据一个回话对象调用QueryInterface即可
- 调用接口的StartTransaction方法开始一个事务
该函数的原型如下
HRESULT StartTransaction (
ISOLEVEL isoLevel,
ULONG isoFlags,
ITransactionOptions *pOtherOptions,
ULONG *pulTransactionLevel);
第一个参数是事务并发的隔离级别,一般最常用的是ISOLATIONLEVEL_CURSORSTABILITY,表示只有最终提交之后才能查询对应数据库表的数据
第二个参数是一个标志,目前它的值必须为0
第3个参数是一个指针,它可以为空,或者是调用ITransactionLocal::GetOptionsObject函数返回的一个指针
第4个参数是调用该函数创建一个事务后,该事务的并发隔离级别
隔离级别是针对不同的线程或者进程的,比如有多个客户端同时在操作数据库时,如果我们设置为ISOLATIONLEVEL_CURSORSTABILITY,那么在同一事务中只有当其中一个客户端提交了事务更新后,另外一个客户端才能正常的进行查询等操作,可以简单的将这个标识视为它在数据库中上了锁,只有当它完成事务后其他客户端才可以正常使用数据库
3. 开始一个事务后正常的进行相关的数据库操作
4. 当所有步骤都正常完成后调用ITransaction::Commit方法提交事务所做的所有修改
5. 或者当其中有一步或者几步失败时调用ITransaction::Abort方法回滚所有的操作
演示例子
//注意使用ISOLATIONLEVEL_CURSORSTABILITY表示最终Commint以后,才能读取这两个表的数据
hr = pITransaction->StartTransaction(ISOLATIONLEVEL_CURSORSTABILITY,0,NULL,NULL);
//获取主表主键的最大值
pRetData = RunSqlGetValue(pIOpenRowset,_T("Select Max(PID) As PMax From T_Primary"));
if(NULL == pRetData)
{
goto CLEAR_UP;
}
iPID = *(int*)((BYTE*)pRetData + sizeof(DBSTATUS) + sizeof(ULONG));
//最大值总是加1,这样即使取得的是空值,起始值也是正常的1
++iPID;
TableID.eKind = DBKIND_NAME;
TableID.uName.pwszName = (LPOLESTR)pszPrimaryTable;
hr = pIOpenRowset->OpenRowset(NULL,&TableID
,NULL,IID_IRowsetChange,1,PropSet,(IUnknown**)&pIRowsetChange);
COM_COM_CHECK(hr,_T("打开表对象'%s'失败,错误码:0x%08X\n"),pszPrimaryTable,hr);
ulChangeOffset = CreateAccessor(pIRowsetChange,pIAccessor,hChangeAccessor,pChangeBindings,ulRealCols);
if(0 == ulChangeOffset
|| NULL == hChangeAccessor
|| NULL == pIAccessor
|| NULL == pChangeBindings
|| 0 == ulRealCols)
{
goto CLEAR_UP;
}
//分配一个新行数据 设置数据后 插入
pbNewData = (BYTE*)COM_CALLOC(ulChangeOffset);
//设置第一个字段 K_PID
*(DBLENGTH *)((BYTE *)pbNewData + pChangeBindings[0].obLength) = sizeof(int);
*(int*) (pbNewData + pChangeBindings[0].obValue) = iPID;
//设置第二个字段 F_MValue
*(DBLENGTH *)((BYTE *)pbNewData + pChangeBindings[1].obLength) = 8;
StringCchCopy((WCHAR*) (pbNewData + pChangeBindings[1].obValue)
,pChangeBindings[1].cbMaxLen/sizeof(WCHAR),_T("主表数据"));
//插入新数据
hr = pIRowsetChange->InsertRow(NULL,hChangeAccessor,pbNewData,NULL);
COM_COM_CHECK(hr,_T("调用InsertRow插入新行失败,错误码:0x%08X\n"),hr);
hr = pIRowsetChange->QueryInterface(IID_IRowsetUpdate,(void**)&pIRowsetUpdate);
COM_COM_CHECK(hr,_T("获取IRowsetUpdate接口失败,错误码:0x%08X\n"),hr);
hr = pIRowsetUpdate->Update(NULL,0,NULL,NULL,NULL,NULL);
COM_COM_CHECK(hr,_T("调用Update提交更新失败,错误码:0x%08X\n"),hr);
COM_SAFEFREE(pChangeBindings);
COM_SAFEFREE(pRetData);
COM_SAFEFREE(pbNewData);
if(NULL != hChangeAccessor && NULL != pIAccessor)
{
pIAccessor->ReleaseAccessor(hChangeAccessor,NULL);
hChangeAccessor = NULL;
}
COM_SAFERELEASE(pIAccessor);
COM_SAFERELEASE(pIRowsetChange);
COM_SAFERELEASE(pIRowsetUpdate);
//插入第二个也就是从表的数据
TableID.eKind = DBKIND_NAME;
TableID.uName.pwszName = (LPOLESTR)pszMinorTable;
hr = pIOpenRowset->OpenRowset(NULL,&TableID
,NULL,IID_IRowsetChange,1,PropSet,(IUnknown**)&pIRowsetChange);
COM_COM_CHECK(hr,_T("打开表对象'%s'失败,错误码:0x%08X\n"),pszMinorTable,hr);
ulChangeOffset = CreateAccessor(pIRowsetChange,pIAccessor,hChangeAccessor,pChangeBindings,ulRealCols);
if(0 == ulChangeOffset
|| NULL == hChangeAccessor
|| NULL == pIAccessor
|| NULL == pChangeBindings
|| 0 == ulRealCols)
{
goto CLEAR_UP;
}
//分配一个新行数据 设置数据后 插入
pbNewData = (BYTE*)COM_CALLOC(ulChangeOffset);
//设置第一个字段 K_MID
*(DBLENGTH *)((BYTE *)pbNewData + pChangeBindings[0].obLength) = sizeof(int);
//设置第二个字段 K_PID
*(DBLENGTH *)((BYTE *)pbNewData + pChangeBindings[1].obLength) = sizeof(int);
*(int*) (pbNewData + pChangeBindings[1].obValue) = iPID;
//设置第二个字段
*(DBLENGTH *)((BYTE *)pbNewData + pChangeBindings[2].obLength) = 8;
StringCchCopy((WCHAR*) (pbNewData + pChangeBindings[2].obValue)
,pChangeBindings[2].cbMaxLen/sizeof(WCHAR),_T("从表数据"));
for(int i = iMIDS; i <= iMIDMax; i++)
{//循环插入新数据
//设置第一个字段 K_MID
*(int*) (pbNewData + pChangeBindings[0].obValue) = i;
hr = pIRowsetChange->InsertRow(NULL,hChangeAccessor,pbNewData,NULL);
COM_COM_CHECK(hr,_T("调用InsertRow插入新行失败,错误码:0x%08X\n"),hr);
}
hr = pIRowsetChange->QueryInterface(IID_IRowsetUpdate,(void**)&pIRowsetUpdate);
COM_COM_CHECK(hr,_T("获取IRowsetUpdate接口失败,错误码:0x%08X\n"),hr);
hr = pIRowsetUpdate->Update(NULL,0,NULL,NULL,NULL,NULL);
COM_COM_CHECK(hr,_T("调用Update提交更新失败,错误码:0x%08X\n"),hr);
//所有操作都成功了,提交事务释放资源
hr = pITransaction->Commit(FALSE, XACTTC_SYNC, 0);
COM_COM_CHECK(hr,_T("事务提交失败,错误码:0x%08X\n"),hr);
CLEAR_UP:
//操作失败,回滚事务先,然后释放资源
hr = pITransaction->Abort(NULL, FALSE, FALSE);
在上述代码中首先创建一个事务对象,然后在进行相关的数据库操作,这里主要是在更新和插入新数据,当所有操作成功后调用commit函数提交,当其中有错误时会跳转到CLEAR_UP标签下,调用Abort进行回滚
最后实例的完整代码:
Trancation
OLEDB事务的更多相关文章
- C# vs MySql
MySqlHelper类 /// <summary> ///MySql操作类 /// </summary> public abstract class MySqlHelper ...
- C#连接、访问MySQL数据库
一.准备工具 visual stuido(本示例使用visual studio 2010) MySql.Data.dll mysql_installer_community_V5.6.21.1_set ...
- DataBase——Mysql的DataHelper
源帖 https://www.cnblogs.com/youuuu/archive/2011/06/16/2082730.html 保护原帖,尊重技术,致敬工匠! using System; usin ...
- 八、.net core 通过数据库配置文件连接操作数据库
一.创建DotNetCore项目 直接创建core项目并不勾选docker支持 二.nuget进行连接MySQL程序集的下载安装 1.MySql.Data.EntityFrameworkCore方式 ...
- DB通用类:MySQL通用类
Mysql类为网络上收集的,没有测试过.. using System; using System.Collections; using System.Collections.Generic; usin ...
- MySql+Socket 完成数据库的增查Demo
需求: 利用MySql数据库结合前端技术完成用户的注册(要求不使用Web服务技术),所以 Demo采用Socket技术实现Web通信. 第一部分:数据库创建 数据库采用mysql 5.7.18, 数据 ...
- C# 基于MySQL的数据层基类(MySQLHelper)
这里介绍下比较简单的方式,引用MySql.Data.dll然后添加一个MySqlHelper类来对MySql数据库进行访问和操作. 1.将MySql.Data.dll引用到你的项目中 下载地址:MyS ...
- C#访问和操作MYSQL数据库
这里介绍下比较简单的方式,引用MySql.Data.dll然后添加一个MySqlHelper类来对MySql数据库进行访问和操作. 1.将MySql.Data.dll引用到你的项目中 下载地址:MyS ...
- MySqlDBHelper数据库连接
这里是本人在工作中用到,希望给大家帮助 public class MySqlDBHelper { //获取一个记录器 private static readonly log4net.ILog log ...
随机推荐
- width:100%以什么为基准的测试
起初是遇到这样一个问题:当盒模型设为box-sizing:border-box;(移动端上经常这么干).子盒子的width:100%,子盒子的width等于父盒子contend的长度还是condend ...
- HMTL5 本地数据库
数据库这个东东现在也可以用在web上了,目前为止, chrom 6 以上版本,opera 10 以上,safari 5以上支持这个功能. htm4中数据库只能放在服务器,只能通过服务器来访问,但是在h ...
- 8、C++指针和自由存储空间
8.C++指针和自由存储空间 计算机程序在存储数据时必须跟踪3中基本属性. 信息存储在何处 存储的值为多少 存储信息是什么类型. 指针是 一个变量,其存储的是值得内存地址 对于常规变量的地址,只需要对 ...
- sql随机插入数据--记录
sql面试题中经常出现一张学生表,表字段有学生ID,学生课程,学生成绩 今天要实测,so,需要有数据,now,随机生成数据,,, create table student ( id ), --编号 c ...
- JDK 5 ~ 10 新特性倾情整理!
JDK 5 ~ 10 新特性倾情整理! 最近连 JDK11都在准备发布的路上了,大家都整明白了吗?也许现在大部分人还在用6-8,8的新特性都没用熟,9刚出不久,10-11就不用说了. 为了大家对JDK ...
- LeetCode记录之21——Merge Two Sorted Lists
算法和数据结构这东西,真的是需要常用常练.这道看似简单的链表合并题,难了我好几个小时,最后还是上网搜索了一种不错算法.后期复习完链表的知识我会将我自己的实现代理贴上. 这个算法巧就巧在用了递归的思想, ...
- kerl build error
删除 archives文件夹就行了
- luogu4931. 情侣?给我烧了!(加强版)(错位排列)
题目链接 https://www.luogu.org/problemnew/show/P4931 题解 以下部分是我最开始的想法. 对于每一个 \(k\),满足恰好有 \(k\) 对情侣和睦的方案数为 ...
- hdu 2654 Be a hero
()Become A Hero Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- linux Ubuntu14.04 python(c++版本) tesorflow(python版本)c++
一.环境变量配置: export M2_HOME=/home/ustcjing/Maven/apache-maven- export JAVA_HOME=/usr/lib/jvm8/java expo ...