Sql server TSQLQuery截断数据
我在2012年问过这个问题: 我想让这个问题保持简单,因此,与其在另一个问题上附加更多细节,希望人们能再看一遍,这是一个新问题,只包含核心细节Sql server TSQLQuery截断数据,sql-server,database,delphi,sql-server-2008-r2,communication,Sql Server,Database,Delphi,Sql Server 2008 R2,Communication,我在2012年问过这个问题: 我想让这个问题保持简单,因此,与其在另一个问题上附加更多细节,希望人们能再看一遍,这是一个新问题,只包含核心细节 问题摘要 TSQLConnection…MaxBobSize有两种设置。使用-1会丢失数据(错误),使用X MB会耗尽内存: TSQLConnection.Params.Values['MaxBlobSize']:='-1',使TSQLQuery查看数据库中每个var.(max)字段的数据长度,并分配与每个字段的数据长度匹配的缓冲区。每个缓冲区中的前1
问题摘要
TSQLConnection…MaxBobSize有两种设置。使用-1
会丢失数据(错误),使用X MB
会耗尽内存:
TSQLConnection.Params.Values['MaxBlobSize']:='-1'
,使TSQLQuery
查看数据库中每个var.(max)
字段的数据长度,并分配与每个字段的数据长度匹配的缓冲区。每个缓冲区中的前1048576字节设置正确,然后剩余字节设置为NULL(0x00
)。因此,数据丢失
TSQLConnection.Params.Values[MaxBlobSize]:=“X MB”
makesTSQLQuery
为查询中返回的每个var.(max)
字段预分配指定的X MB
内存X MB
必须足够大,以容纳最大的var.(max)
对象。即使在10MB
,一个包含3个var.(max)
字段和100行的查询将预先分配3GB
内存来为查询服务,即使实际数据要小得多。如果机器内存不足,用户会看到“灾难性故障”
详细信息
2012年,我们与Embarcadero合作解决了bug#1。他们所说的使用xmb
而不是-1
,这会导致我们的用户体验到状况2。我们继续使用MaxBlobSize:=-1
希望Embarcadero最终能够修复#1,或者我们的用户永远不会超过1MB限制
一个用户向数据库上传了一个10MB的图像,这种情况很可能再次发生。当他们检索10MB图像时,前1MB图像显示正确,其余图像丢失。完整的10MB图像正确存储在数据库中。因此,用户遇到了错误1
这个问题仍然存在于DelphiSeattle(XE10)中,正如这个简单的测试用例所演示的。我通过WireShark验证了来自db的流量包括所有字段数据
创建一个新的Delphi VCL表单项目
将SQLConnection1:TSQLConnection
添加到表单中,设置以访问数据库:
- 驱动程序=MSSQL
- 主机名=本地主机
- OSAuthentication=True
- 数据库=tempdb
- LoginPrompt=False
将SQLConnection1.Params['MaxBlobSize']
设置为-1
使用以下OnClick()
code添加按钮1:t按钮
:
procedure TForm1.按钮1点击(发送方:TObject);
变量
qry:TSQLQuery;
过程保存(fn:字符串);
变量
数据:t字节;
fs:TFileStream;
开始
fs:=TFileStream.Create('c:\'+fn+'.txt',fmCreate);
尝试
数据:=qry.FieldByName(fn).AsBytes;
如果数据为零,则
fs.WriteBuffer(数据[0],长度(数据));
最后
FreeAndNil(fs);
结束;
结束;
开始
SQLConnection1.Open;
qry:=TSQLQuery.Create(nil);
尝试
qry.MaxBlobSize:=-1;
qry.SQLConnection:=SQLConnection1;
qry.SQL.Text:=Concat(
'声明@s1 varchar(最大值),@s2 varchar(最大值)',
'set@s1='0123456789ABCDEF',
“set@s2=@s1+@s1+@s1+@s1+@s1+@s1+@s1/*128字节*/”,
“set@s1=@s2+@s2+@s2+@s2+@s2+@s2+@s2+@s2/*1024字节*/”,
'set@s2=@s1+@s1+@s1+@s1+@s1+@s1+@s1/*8192字节*/',
“set@s1=@s2+@s2+@s2+@s2+@s2+@s2+@s2+@s2/*65536字节*/”,
“set@s2=@s1+@s1+@s1+@s1+@s1+@s1+@s1/*524288字节*/”,
'set@s1=@s2+@s2/*1048576字节*/',
'set@s2=@s1+''这是一个测试'/*1MB+14字节*/',
紧急广播系统“/*1MB+36字节*/”的“set@s1=@s1+”,
'选择@s2作为Plus14,@s1作为Plus36'
);
qry.打开;
保存(“Plus14”);
保存(“Plus36”);
最后
FreeAndNil(qry);
结束;
SQLConnection1.Close;
结束;
运行应用程序并单击按钮
在十六进制编辑器中打开每个文件,并在每个文件末尾查找空值(0x00
)
问题
由于用户在使用MaxBobSize:=X MB
时遇到内存不足问题,我们需要保持MaxBobSize:=-1
。是否有人有任何建议或解决方案可以将MaxBlobSize
设置为-1
,继续使用TSQLConnection
和TSQLQuery
,然后访问所有字段数据,即使字段超过1MB
如果无法使用上述组件,则使用本机组件的另一种解决方案也可以。FWIW我使用TADO。。。组件,并且从来没有任何数据大小问题。一直存储和检索图像…我同意@Peter的观点。我承认,我一点也不清楚为什么要将dbExpress与Sql Server结合使用——这会让你依赖EMBA来修复它们的bug,而且在任何情况下,Delphi附带的TAdo*组件都是围绕MS经过尝试和测试的ADO层的相对较薄的包装,后者的用户基础要大得多,因此bug要少得多。如果使用TAdo*组件fwiw在Delphi中开发,我自己20年来从未遇到过ADO错误。这两个都是非常好的评论。我修改了问题中的测试用例以使用ADO组件,您是对的,它们在没有提到问题的情况下工作。是时候切换到ADO了。我之所以使用dbExpress组件,是因为我们使用了DataSnap,并且已经将dbExpress与DataSnap一起使用了。吸取的教训。。。