Ao migrar ambientes de desenvolvimento ou produção de versões legadas do MySQL (como a 5.1) para versões mais recentes (como a 8.0), desenvolvedores frequentemente encontram comportamentos distintos na validação de tipos de dados. Um problema comum ocorre ao tentar inserir strings vazias em colunas definidas como inteiras.
Mudanças no Comportamento do MySQL
Existem dois pontos fundamentais que alteraram a percepção e o funcionamento do banco de dados em versões recentes:
- Largura de Exibição (Display Width): A partir da versão 8.0.17, o MySQL descontinuou o suporte para a largura de exibição em tipos inteiros (como
INT(10)). Isso significa que, ao salvar a estrutura de uma tabela, o Navicat ou outras ferramentas podem exibir o comprimento como 0 ou omiti-lo, pois essa configuração não afeta mais o armazenamento ou o intervalo de valores. - Modo Estrito: Versões modernas operam por padrão com modos SQL mais rigorosos. Enquanto o MySQL 5.1 convertia silenciosamente uma string vazia (
'') para0ao inserir em um campoINT, o MySQL 8.0 gera o erro1366: Incorrect integer value.
Demonstração do Problema
O código abaixo exemplifica uma tentativa de inserção que funciona no MySQL 5.1, mas falha no MySQL 8.0:
import pymysql
# Configuração de conexão
config = {
'host': 'localhost',
'user': 'root',
'password': 'sua_senha',
'database': 'ecommerce'
}
username = 'DevSenior'
score = '' # Representando um dado ausente vindo de um formulário ou crawler
conn = pymysql.connect(**config)
try:
with conn.cursor() as cursor:
sql = "INSERT INTO perfil_usuario (nome, pontuacao) VALUES (%s, %s)"
cursor.execute(sql, (username, score))
conn.commit()
except pymysql.MySQLError as err:
print(f"Erro na transação: {err}")
conn.rollback()
finally:
conn.close()
No MySQL 8.0, o resultado será: (1366, "Incorrect integer value: '' for column 'pontuacao' at row 1").
Solução Técnica: Higienização de Dados
A abordagem mais robusta para resolver este impasse é garantir que a lógica da aplicação trate os dados antes de enviá-los para a camada de persistência. Em vez de depender de conversões implícitas do motor de banco de dados, devemos converter explicitamente strings vazias em 0 ou None (que será interpretado como NULL).
Abaixo, apresento uma implemantação de um método de inserção genérico que realiza a limpeza automática de campos específicos:
def salvar_registro(self, nome_tabela, dicionario_dados):
"""
Insere dados em uma tabela, tratando strings vazias para evitar erros de tipo.
"""
# Lista de campos que devem ser obrigatoriamente numéricos
campos_numericos = ['vendas', 'comentarios', 'pontuacao']
# Sanitização: converte strings vazias em 0 para campos numéricos
for campo in campos_numericos:
if dicionario_dados.get(campo) == '':
dicionario_dados[campo] = 0
colunas = ', '.join(dicionario_dados.keys())
marcadores = ', '.join(['%s'] * len(dicionario_dados))
query_sql = f"INSERT INTO {nome_tabela} ({colunas}) VALUES ({marcadores})"
try:
self.cursor.execute(query_sql, tuple(dicionario_dados.values()))
self.db.commit()
except pymysql.MySQLError as erro:
print(f"Falha ao persistir dados: {erro.args}")
self.db.rollback()
Considerações sobre NULL vs 0
Dependendo da regra de negócio, pode ser mais apropriado converter a string vazia para None em vez de 0. No Python, ao passar None para o pymysql, o driver enviará o comando NULL para o MySQL. Isso é útil quando você precisa distinguir entre um valer zerado e um valor não informado, desde que a coluna no banco de dados permita valores nulos.
# Exemplo de conversão para NULL
if data.get('comments') == '':
data['comments'] = None
Ao adotar essa prática de sanitização, o código torna-se independente da versão do servidor MySQL, evitando quebras inesperadas durante atualizações de infraestrutura.