【求助】从CListCtrl里面把数据写到数据库里面,顺序错误的问题

Squall001 2014-06-02 01:24:03
编译环境VC6 ,操作系统为XP SP3,SQL server 2000 数据库,下面说下我整个操作流程, 在一个基于对话框窗口的应用程序里面,有一个CListCtrl这个列表框控件,在列表框控件里面有4列 分别放了一些数据,其中一列的数据可能有几百个字符,这个不一定。然后我把这个列表框里面的数据依次保存到数据库里面的一张表里面。程序连接数据库用ADO封装的类来操作。
下面是我数据库里面表属性的截图



下面给出相关操作数据库的代码
先是ADO类的头文件
///////////////////////////ADO.h
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
class CAdo
{
public:
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecordset;
public:
CAdo();
virtual ~CAdo();
// 初始化—连接数据库
void OnInitADOConn();
// 执行查询
_RecordsetPtr& GetRecordSet(CString strSQL);

void close();
// bool Move(int nRecordNumber);
bool MovePrevious();
bool MoveLast();
bool MoveNext();
bool MoveFirst();
int GetRecordCount();
//void Open(CString TSQL);
bool Open(CString srecordset, UINT adCmd);
void GetErrors(_com_error eErrors);
CString GetFieldValue(CString Field);
void AddNew();
void Update();
bool Move(int nRecordNum);
void SetFieldValue(CString OField,CString value);
void ExecuteSQL(CString SQL);
bool recordeof();
bool recordbof();
void rstOpen(CString TSQL);
};


上面这么多函数 实际值用到了4个


/////////////////////////下面给出ADO.CPP对于本问题有关的函数
void CAdo::OnInitADOConn() //初始化ADO
{
// 初始化OLE/COM库环境
::CoInitialize(NULL);
try
{
// 创建Connection对象
m_pConnection.CreateInstance("ADODB.Connection");
// 设置连接字符串,必须是BSTR型或者_bstr_t类型
m_pConnection->Open((_bstr_t)strAdoConn,"","",adModeUnknown); //这里的strAdoConn是全局变量里面的,从InitInstance()获取,在文件上方声明的extern。
}
// 捕捉异常
catch(_com_error e)
{
// 显示错误信息
AfxMessageBox(e.Description());
}
}
void CAdo::ExecuteSQL(CString TSQL) //执行SQL语句
{
try
{
m_pConnection->Execute((_bstr_t)TSQL,NULL,adCmdText);
}
catch(_com_error e)
{
AfxMessageBox(e.Description());
}
}

_RecordsetPtr& CAdo::GetRecordSet(CString strSQL) // 执行查询
{
try
{
// 连接数据库,如果Connection对象为空,则重新连接数据库
if(m_pConnection==NULL)
OnInitADOConn();
// 创建记录集对象
m_pRecordset.CreateInstance(__uuidof(Recordset));
// 取得表中的记录
m_pRecordset->Open((_bstr_t)strSQL,m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
}
// 捕捉异常
catch(_com_error e)
{
// 显示错误信息
AfxMessageBox(e.Description());
}
// 返回记录集
return m_pRecordset;
}

void CAdo::close() //关闭ADO
{
if(m_pRecordset!=NULL)
m_pRecordset->Close();
m_pConnection->Close();
m_pRecordset=NULL;
m_pConnection=NULL;
::CoUninitialize();
}



下面是程序的执行代码,把CListCtrl这个列表框控件里面的数据全部保存到数据库一张表里面去。


CAdo ado;
ado.OnInitADOConn();
CString seqid,executename,usemodule,useparameter,sql;
UpdateData(true); //更新读取m_EditProdSerial m_EditProdItem 两个CString变量用的
int i,listcount;
listcount=m_listctrl.GetItemCount(); //获取列表框有多少行 m_listctrl关联列表框控件
for(i=0;i<listcount;i++) //for循环 去执行SQL语句 把数据写进数据库里面。
{
//把第i行里面4列的数据全部读到CString变量里里面
seqid=m_listctrl.GetItemText(i,0);
executename=m_listctrl.GetItemText(i,1);
usemodule=m_listctrl.GetItemText(i,2);
useparameter=m_listctrl.GetItemText(i,3);

if(i==0) //在第一次操作的时候,先删除表里面的数据。
{
sql="Truncate Table ";
sql+="_"+m_EditProdSerial+"_"+m_EditProdItem;
ado.ExecuteSQL(sql); //清空表
}


sql="insert into ";
sql+="_"+m_EditProdSerial+"_"+m_EditProdItem;
sql+=" (seq_id,productserial,productitem,usemodule,useparameter,executename)values(";
sql+=seqid+",'"+m_EditProdSerial+"','"+m_EditProdItem+"','"+usemodule+"','"+useparameter+"','"+executename+"')";
//上面的SQL语句合起来的语句为以下这种形式
/*
insert into _A001_000002 (seq_id,productserial,productitem,usemodule,useparameter,executename)values(1,'A001','000002','电源1路','24;','设置电源24伏')
_A001_000002就是表名 productserial,productitem这两个变量组合起来就是表名
但是对于useparameter这个变量里面 可能有几百个字符。
*/
ado.ExecuteSQL(sql);
}
ado.close();



我列表框里面的数据,多的时候可能有200多行,每一列里面字符数不定,可能几个字符,可能几百个字符。

现在问题出来了,我执行这个for循环就是在主UI线程里面执行的,数据库就在本地电脑上面。所以执行的时候会明显感觉到卡一下。我用的SQL语句 是insert into 这种应该是默认加到最后表里面的最后一行把,但是实际情况却不是这样的,在前面几十行的数据都是正确的,但是到了后面,行数就变了,但是总的行数还是有这么多,但是具体的行顺序就变了

比如说 一张表有100行 我每一行第一列都有序号,这个序号是在表格控件里面递增的。当时通过上面的for循环后 我从数据库里面打开表里面看数据 ,就发现 前面80行的数据都正确,但是到了81行的时候,这时的数据应该是81行的吧,但是数据库里面显示的是90行的数据,而第90行里面可能就显示的是81行的数据,也可能是其他行的数据,但是总共有100行。100行的数据还是完整的,只是里面的顺序错了。

需要说明的是,我CListCtrl控件里面的数据绝对是严格递增,正确的,但是读到数据库里面后顺序就乱了。

下面是具体错误顺序的截图


下面是问题的一点分析。在程序里面,假设执行100个for循环的 ado.ExecuteSQL(sql);只要1秒,但是数据库要把100个数据写到表里面去要10秒,这中间就有时间差,可能数据库还在处理第50次ado.ExecuteSQL(sql)得时候,这边for循环已经到了第80次了,期间的30次ado.ExecuteSQL(sql)就全部挂在数据库上面了。我想ado.ExecuteSQL(sql)这种语句可能是用PostMessage的方式放到队列里面就马上返回,而不是等待执行完了再返回。而数据库那边每次从队列里面取SQL语句来执行,它是不是看,把容易执行的就先执行了,比如那些字符多的,我里面有几百个字符的,就挂在那里,等空了再来执行。这样一来,虽然总数是对的,但是顺序就错了。

如果是我描述那样的话,我怕如果我一个for循环的次数多了,岂不是就超出数据库用于把数据挂在那里的缓存了,这样就会丢失数据?这个是非常担心的一个问题1。
还有一个问题2就是,怎么让数据库和程序有类似waitforsingleobject那种的同步,程序等待数据库执行完了一个ado.ExecuteSQL(sql)过后,程序再去执行下一条for循环,这样就保证顺序不会错了。


目前我的临时解决办法,就是在取表里面的数据的时候 加一个order by 排序一下,再从记录集里面取到表格里面,这样看起来就是顺序正确的了,但是表里面的数据还是顺序乱的。


...全文
381 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
野生大猫 2014-06-03
  • 打赏
  • 举报
回复
查看下表属性,有没有什么触发器什么的,排序规则
worldy 2014-06-03
  • 打赏
  • 举报
回复
数据保存记录不保证保存顺序,一般记录可以通过主键进行定位,在支持书签的提供者,则可以使用书签进行定位
Squall001 2014-06-02
  • 打赏
  • 举报
回复
引用 5 楼 zyq5945 的回复:
没加Orderby排序的查询的结构顺序都是未知的,和插入先后没有关系 ado.ExecuteSQL(sql)是把SQL语句发送给数据库端,等待数据库端解释与执行SQL,然后才返回
原来如此 谢谢讲解啦
zyq5945 2014-06-02
  • 打赏
  • 举报
回复
没加Orderby排序的查询的结果顺序都是未知的,和插入先后没有关系
ado.ExecuteSQL(sql)是把SQL语句发送给数据库端,等待数据库端解释与执行SQL,然后才返回
Squall001 2014-06-02
  • 打赏
  • 举报
回复
引用 3 楼 zyq5945 的回复:
ado.ExecuteSQL(sql)是把SQL语句发送给数据库端,等待数据库端解释与执行SQL,然后才返回,有错误的话会在catch里得到这个错误,没有错误的话就是已经执行成功了。
原来是这样 但是 你说他已经执行了再返回,那为什么还会出现顺序错误的情况? 是不是只是解释了就返回,而没有执行
zyq5945 2014-06-02
  • 打赏
  • 举报
回复
ado.ExecuteSQL(sql)是把SQL语句发送给数据库端,等待数据库端解释与执行SQL,然后才返回,有错误的话会在catch里得到这个错误,没有错误的话就是已经执行成功了。
Squall001 2014-06-02
  • 打赏
  • 举报
回复
引用 1 楼 zyq5945 的回复:
不需要关心数据库中数据次序,真需要排序的时候都是Order By排序。 执行ExcuteSQL没有错误的话就可以认为是插入成功了。 需要同步的话可以搜下"SQL SERVER 事务".
你的意思是说 如果ado.ExecuteSQL(sql);执行了 没有报错 就一定执行成功了的,如果报错才是没有执行成功? 根据上面的代码ado.ExecuteSQL(sql);内部是try.......catch的结构 也就是 如果执行不成功 就会被catch到? 另外 我的程序现在不需要同步 但是需要把数据全部正确的加载到数据库里面,只要确保加载完了的,顺序都没有关系 ,我就怕 如果我加载的数据多了,它要是真的报错了,我就麻烦了,就不知道怎么改啊。 所以我需要了解ado.ExecuteSQL(sql);的具体执行属性,它执行的时候,是等待数据库那边返回个什么信号 才能结束执行么?如果这样的话 我就完全不怕了,实际上已经同步了,出现顺序错误也是数据库自己内部优化的问题了。 但是ado.ExecuteSQL(sql);只是把数据发给数据库,也不管数据库那边收到没有,就执行下一句,这种就有点危险了,如果是这种情况 我该怎么改?
zyq5945 2014-06-02
  • 打赏
  • 举报
回复
不需要关心数据库中数据次序,真需要排序的时候都是Order By排序。 执行ExcuteSQL没有错误的话就可以认为是插入成功了。 需要同步的话可以搜下"SQL SERVER 事务".

4,012

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 数据库
社区管理员
  • 数据库
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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