【问题标题】:Python mysql timestamp insert does not work but will work in mysql clientPython mysql时间戳插入不起作用但可以在mysql客户端中工作
【发布时间】:2015-02-09 23:46:24
【问题描述】:

在 mysql 客户端中,以下查询可以完美运行:

 INSERT  INTO VOLUMES (VOLUMEID, NAME, TYPE, SERVERID,SIZE, DEVICENAME, CREATIONDATE) VALUES ('vol-b67d73b7', 'TBC','gp2', 'i-7d445a89', '8', '/dev/sda1', '2014-11-24T07:40:37.921Z');

但是,当我在我的 python 脚本中使用相同的查询时,我收到以下错误:

1265: Data truncated for column 'CREATIONDATE' at row 1

这是python代码:

try:
  db = mysql.connector.connect(**config)
   cursor = db.cursor()

  for volume in volumes:
    ins_stmt = ("INSERT  INTO VOLUMES (VOLUMEID, NAME, TYPE, SERVERID,"
            "SIZE, DEVICENAME, CREATIONDATE) VALUES ('{0}', 'TBC',"
            "'{1}', '{2}', '{3}', '{4}', '{5}');")
    to_execute = ins_stmt.format( volume.id, volume.type,
            volume.attach_data.instance_id, volume.size,
            volume.attach_data.device, volume.create_time)
    cursor.execute(to_execute)

except mysql.connector.Error as err:
  if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
    print("Something is wrong with your user name or password")
  elif err.errno == errorcode.ER_BAD_DB_ERROR:
    print("Database does not exists")
  else:
    print(err)
else:
  db.close()

我不明白可能出了什么问题。有人可以帮忙吗?

【问题讨论】:

  • @MartijnPieters 已编辑,谢谢。
  • 您不应该使用str.format 将值插入到查询中,这是一个巨大的SQL injection 风险。请查看the docs 了解如何完成的示例。

标签: python mysql timestamp


【解决方案1】:

您需要使用 SQL 参数 并让数据库适配器为您处理引用:

ins_stmt = ("INSERT  INTO VOLUMES (VOLUMEID, NAME, TYPE, SERVERID,"
        "SIZE, DEVICENAME, CREATIONDATE) VALUES (?, 'TBC',"
        "%s, %s, %s, %s, %s);")
params = (volume.id, volume.type,
        volume.attach_data.instance_id, volume.size,
        volume.attach_data.device, volume.create_time)
cursor.execute(to_execute, params)

这不仅可以确保您不会遇到与字符串中预先存在的引用字符有关的问题,还可以避免 SQL 注入攻击(用户制作的数据会中断引用并发出额外的 SQL 语句)无意允许)。不要让 Little Bobby Tables 抓住你!

接下来,确保您的时间戳采用MySQL supports 的格式;您的时间戳似乎有一个 3 位小数和一个时区说明符; MySQL 5.6.4 及更高版本似乎需要 6 位小数、空格而不是 T,并且没有时区,所以也许您应该从 volume.create_time 字符串中删除该部分:

params = (volume.id, volume.type,
          volume.attach_data.instance_id, volume.size,
          volume.attach_data.device,
          volume.create_time.replace('T', ' ').partition('.')[0])

您看到的消息是告诉您 MySQL 不会接受格式化的日期。您的 MySQL 客户端要么仅发出 警告(而不是错误),要么配置为允许无效日期(设置了ALLOW_INVALID_DATES)。如果设置了警告,您需要在客户端使用show warnings 向 MySQL 询问警告。

【讨论】:

  • @user1658296:您尝试打印params 包含的内容吗?也许您的volume.create_time 值并不像您认为的那样。
  • @user1658296:但您刚刚声称该格式适用于您的 MySQL 客户端。看dev.mysql.com/doc/refman/5.6/en/datetime.html末尾的Z是不支持的,小数应该是6位,而不是3位。
  • @user1658296:可能是您在使用客户端时使用较旧的 MySQL 服务器进行了测试?无论如何,只有 5.6.4 及更高版本支持分数;在较旧的 MySQL 服务器中,小数部分被丢弃。
  • 这就是我觉得很奇怪的地方。我在同一台服务器上对其进行了测试。我现在将尝试正确格式化日期时间。
  • @user1658296:了解有关 MySQL 和日期格式的更多信息。您的格式确实不正确,但 MySQL 客户端已配置为忽略无效日期,或者您忽略了正在发出的警告;运行show warnings; 以显示发出的警告,它应该显示相同的消息。
猜你喜欢
  • 1970-01-01
  • 2017-11-21
  • 2011-08-27
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 2018-01-26
  • 1970-01-01
相关资源
最近更新 更多