我正在尝试将我的数据从SQLite迁移到MySQL数据库,但这个奇怪的问题一再出现。
我有这个表,与其他表无关:
CREATE TABLE `tableClassesNacionaisH` (
`id` int(11) DEFAULT NULL,
`nome` varchar(255) DEFAULT NULL,
`situacao` varchar(255) DEFAULT NULL,
`codigoNacional` int(11) DEFAULT NULL,
`codigoNacionalPai` int(11) DEFAULT NULL,
`natureza` varchar(255) DEFAULT NULL,
`dispositivoLegal` varchar(255) DEFAULT NULL,
`artigo` varchar(255) DEFAULT NULL,
`sigla` varchar(255) DEFAULT NULL,
`poloAtivo` varchar(255) DEFAULT NULL,
`numeracaoPropria` varchar(255) DEFAULT NULL,
`glossario` text,
`lft` int(11) DEFAULT NULL,
`lvl` int(11) DEFAULT NULL,
`rgt` int(11) DEFAULT NULL,
`root` int(11) DEFAULT NULL,
`justEs1Grau` varchar(11) DEFAULT NULL,
`justEs2Grau` varchar(11) DEFAULT NULL,
`justEsJuizadoEs` varchar(11) DEFAULT NULL,
`justEsTurmas` varchar(11) DEFAULT NULL,
`justEs1GrauMil` varchar(11) DEFAULT NULL,
`justEs2GrauMil` varchar(11) DEFAULT NULL,
`justEsJuizadoEsFp` varchar(11) DEFAULT NULL,
`justTuEsUn` varchar(11) DEFAULT NULL,
`justFed1Grau` varchar(11) DEFAULT NULL,
`justFed2Grau` varchar(11) DEFAULT NULL,
`justFedJuizadoEs` varchar(11) DEFAULT NULL,
`justFedTurmas` varchar(11) DEFAULT NULL,
`justFedNacional` varchar(11) DEFAULT NULL,
`justFedRegional` varchar(11) DEFAULT NULL,
`justTrab1Grau` varchar(11) DEFAULT NULL,
`justTrab2Grau` varchar(11) DEFAULT NULL,
`justTrabTst` varchar(11) DEFAULT NULL,
`stf` varchar(11) DEFAULT NULL,
`stj` varchar(11) DEFAULT NULL,
`cjf` varchar(11) DEFAULT NULL,
`cnj` varchar(11) DEFAULT NULL,
`justMilUniao1Grau` varchar(11) DEFAULT NULL,
`justMilUniaoStm` varchar(11) DEFAULT NULL,
`justMilEst1Grau` varchar(11) DEFAULT NULL,
`justMilEstTjm` varchar(11) DEFAULT NULL,
`justElei1Grau` varchar(11) DEFAULT NULL,
`justElei2Grau` varchar(11) DEFAULT NULL,
`justEleiTse` varchar(11) DEFAULT NULL,
`criadoEm` datetime DEFAULT NULL,
`atualizadoEm` datetime DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
`poloPassivo` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
为了隔离错误,我编写了这个测试程序:
Private Shared Sub TestSub()
Dim command_text As String = "SELECT * FROM atena.tableClassesNacionaisH;"
Dim connection As MySql.Data.MySqlClient.MySqlConnection = AppSet.Atena.Connection
Dim command As New MySql.Data.MySqlClient.MySqlCommand(command_text, connection)
Dim table As New DataTable
Dim dataexception As Exception = Nothing
Dim rowsinerror As DataRow() = {}
connection.Open()
Try
table.Load(command.ExecuteReader)
Catch dataexception
End Try
connection.Close()
rowsinerror = table.GetErrors
If dataexception IsNot Nothing Then
Debug.Print(dataexception.GetType.ToString)
Debug.Print(dataexception.Message)
For Each rowinerror In rowsinerror
Debug.Print(rowinerror.RowError)
Next
Debug.Print(table.Columns("glossario").MaxLength)
End If
End Sub
按顺序,这些是异常类型,异常消息,第1行错误(英语翻译为我的)和table.Columns("glossario").MaxLength
的值:
System.Data.ConstraintException
激活限制失败。一行或多行包含违反非null,唯一或外键限制的值。
列'glossario'超出MaxLength限制。
21845
由于我不知道这个数字(21845)是如何被推断的,所以我去了MySQL Workbench并运行了以下查询:
SELECT max(length(glossario)) FROM tableClassesNacionaisH;
结果是34504。
现在问题在于:
*为什么列glossario
的MaxLength设置为 21845 ,如果来自该特定查询的实际内容 可以与 34504 <一样长/ strong>和TEXT DataType has maximum length of 65535 characters?
我该如何预防/规避这个问题?*
非常感谢。
编辑:一位朋友指出,21845正好是65535的1/3,这让我怀疑这个问题与charset有关。我通过将列的数据类型更改为MEDIUMTEXT来规避它,从而将上限方式提升到16,777,215个字符(或字节?,我不再确定)。但问题仍然存在:MySQL 在TEXT列中存储了一个34504长的字符串而没有截断它。 CLR类型System.String没有21845或65535个字符的这种下限(假设它可能包含大约10亿个字符,但我很少用......)。
答案 0 :(得分:1)
在您提供的链接中,它明确指出对于TEXT字段,“如果值包含多字节字符,则有效最大长度会减少。”
UTF-8是Unicode Charset,是数据库的默认值。它对前128个字符使用1字节表示,与ASCII集匹配,对其余字符使用4字节表示。
这意味着TEXT列可以存储更多或更少的字符,具体取决于字符是否为ASCII。
现在,当MySQL驱动程序无法正确处理此问题时,您的问题就出现了,将假设所有UTF-8字符都是4字节宽,并将列长度除以4个字节,将其作为实际字段长度传递给DataTable。这意味着在技术上可以在数据库中包含一些不适合DataTable的文本,就像你的情况一样。
您的问题的解决方案(或本例中的解决方法)正是您现在所做的,即将列更改为可包含更多字符的类型,如MEDIUMTEXT或LONGTEXT。
我的猜测是这个决定是为了简化MySQL驱动程序的实现,但我会考虑向Oracle提交错误报告。