编译环境VC6 ,操作系统为XP SP3,SQL server 2000 数据库,下面说下我整个操作流程, 在一个基于对话框窗口的应用程序里面,有一个CListCtrl这个列表框控件,在列表框控件里面有4列 分别放了一些数据,其中一列的数据可能有几百个字符,这个不一定。然后我把这个列表框里面的数据依次保存到数据库里面的一张表里面。程序连接数据库用自用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 ExecuteSQL(CString SQL);
//关闭ADO
void close();
};
//下面是对应的具体函数
/下面给出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语句 把数据写进数据库里面。
{ //这个FOR循环的意思就是获取每一行的数据,依次执 //行ado.ExecuteSQL(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)value s(1,'A001','000002','电源1路','24;','设置电源24伏')
_A001_000002就是表名 productserial,productitem这两个变量组合起来就是表名
但是对于useparameter这个变量里面 可能有几百个字符。
*/
ado.ExecuteSQL(sql); //执行SQL语句
}
//以上FOR循环结束后关闭ADO
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语句来执行,它是不是看,把容易执行的就先执行了,比如那些字符多的,我里面有几百个字符的,就挂在那里,等空了再来执行。这样一来,虽然总数是对的,但是顺序就错了。
问题1
如果是我描述那样的话,我怕如果我一个for循环的次数多了,岂不是就超出数据库用于把数据挂在那里的缓存了,这样就会丢失数据?这个是非常担心的一个 问题1。
问题2
还有一个 问题2 就是,怎么让数据库和程序有类似WaitForSingleObject,那种的类似用于多线程的同步的机制,程序等待数据库执行完了一个ado.ExecuteSQL(sql)过后,程序再去执行下一条for循环,这样就保证顺序不会错了。
目前我的临时解决办法,就是在取表里面的数据的时候 加一个order by 排序一下,再从记录集里面取到表格里面,这样看起来就是顺序正确的了,但是表里面的数据还是顺序乱的,我也无法检测插入到数据库里面数据的完整性,唯一的报错验证就是在在ExecuteSQL(sql)函数里面的try().....catch(),结构 如果没有catch到 就默认正确。