日期:2014-05-16  浏览次数:20871 次

Mysql同一个事务内记录成功插入后查询不出来
背景:
1)mysql:Ver 14.12 Distrib 5.0.45, for Win32 (ia32)
2)mysql odbc驱动:3.51.22
3)vs2005
4)客户端用ado,odbc驱动连接mysql数据库
5)表tb_5100定义如下:
CREATE TABLE `tb_5100` (
  `account_id` BIGINT(20) NOT NULL,
  `service_id` INT(11) NOT NULL,
  `f002d_5105` DATE NOT NULL,
  `object_id` INT(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY  (`object_id`)
) ENGINE=INNODB DEFAULT CHARSET=gbk;
object_id字段AUTO_INCREMENT(自增长)
f002d_5105字段date类型,不能为空

问题:
开启一个事务
往tb_5100表插入一条记录,f002d_5105为空或者''(违反非空约束);
获取新记录的自增长字段object_id的值
根据自增长字段object_id查询新记录查不出来
提交事务
记录已经插入到数据库中,用mysql客户端工具可以查询出记录。
示例代码如下所示:
pdbor->BeginTrans();
string sql = "INSERT INTO tb_5100(account_id,service_id,f002d_5105) VALUES(10068,300,'')";
if( !pdbor->Execute(adCmdText,sql.c_str()) ){
pdbor->RollbackTrans();
return -1;
}
///<获得自增长字段值
unsigned __int64 service_serial;
if( pdbor->GetDBExt()->GetLastID(service_serial,1,"") ){
pdbor->RollbackTrans();
return -2;
}
sql = LogMsg("SELECT * FROM tb_5100 where object_id=%d",service_serial);
CRecordset *prs = pdbor->Query(adCmdText,sql.c_str());
if( prs == NULL ){
pdbor->RollbackTrans();
return -3;
}
if( prs->IsEof() ){
pdbor->RollbackTrans();
return -4;///<查询不出来,函数返回-4
}
pdbor->CommitTrans();
return 0;

经多次实验,
将f002d_5105字段改为允许为NULL,记录可以成功插入,在事务内,可以查询出新记录。
将数据库模式设置为STRICT_TRANS_TABLES严格模式(修改my.ini,在[mysqld]段,设置sql-mode="STRICT_TRANS_TABLES"),insert失败。

分析:
导致问题的原因为日期型字段f002d_5105数据非法的问题。新记录插入后,f002d_5105字段的值为'0000-00-00',为非法的日期型数据。MySQL是允许无效数据的存在的。详见http://it.china-b.com/sjk/mysql/20090828/179324_1.html(mysql中对无效数据的约束)。
而由于非法数据,导致同一个事务内能插入成功,但查询不来的问题,确实不解,这可能跟驱动有关,但只是个猜测。
解决此问题的办法应该是避免出现无效数据,应该使用严格的约束模式,即STRICT_TRANS_TABLES。参见http://www.zhixing123.cn/php/MYSQL%20STRICT_TRANS_TABLES.html。

参考:
http://it.china-b.com/sjk/mysql/20090828/179324_1.html
http://www.zhixing123.cn/php/MYSQL%20STRICT_TRANS_TABLES.html

在MySQL5.0.2之前,MySQL对非法或不当值并不严厉,而且为了数据输入还会强制将它们变为合法值。在MySQL5.0.2和更高版本中,保留了以前的默认行为,但你可以为不良值选择更传统的处理方法,从而使得服务器能够拒绝并放弃出现不良值的语句。本节介绍了MySQL的默认行为(宽大行为),新的严格的SQL模式,以及它们的区别。如果你未使用严格模式,下述情况是真实的。如果将“不正确”的值插入到列,如将NULL值插入非NULL列,或将过大的数值插入数值列,MySQL会将这些列设置为“最可能的值”,而不是生成错误信息。如果试图将超范围的值保存到数值列,MySQL服务器将保存0(最小的可能值)取而代之,或最大的可能值。对于字符串,MySQL或保存空字符串,或将字符串尽可能多的部分保存到列中。如果打算将不是以数值开头的字符串保存到数值列,MySQL将保存0。MySQL允许将特定的不正确日期值保存到DATE和DATETIME列(如“2000-02-31”或“2000-02-00”)。其观点在于,验证日期不是SQL服务器的任务。如果MySQL能保存日期值并准确检索相同的值,MySQL就能按给定的值保存它。如果日期完全不正确(超出服务器能保存的范围)将在列中保存特殊的日期值“0000-00-00”取而代之。如果试图将NULL值保存到不接受NULL值的列,对于单行INSERT语句,将出现错误。对于