`
丁林.tb
  • 浏览: 797060 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

MySQL关于timestamp和mysqldump的一个“bug”

阅读更多

复现

来源于一个同事在做数据转储碰到的的问题,简化如下:

1、建表

drop table if exists tb;

CREATE TABLE tb (

  c timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

insert into tb values(now());

select * from tb;

 

返回

mysql> select * from tb;

+---------------------+

| c                   |

+---------------------+

| 2012-12-14 00:42:45 |

+---------------------+

1 row in set (0.00 sec)

 

2dump“出错”

  mysqldump   -Srun/mysql.sock -uroot   test tb   --where='c="2012-12-14 00:42:45"' | grep INSERT

返回为空,也就是说导不到数据。

 

 

分析

从上面的结论看上去,似乎是mysqldump”bug”,看得到的数据都导不出来。 如果我们先不加where条件,

mysqldump   -Srun/mysql.sock -uroot   test tb    |grep INSERT                         

INSERT INTO `tb` VALUES ('2012-12-13 16:42:45');

 

接下来我们要说说关于timestamp这个字段类型。

首先,从大小上你可以看出来,它不是个字符串,实际上是一个整型。所以当我们执行 where c=” 2012-12-14 00:42:45的时候,需要将其转换为整型。这就涉及到转换规则。也就是说,对于相同的时间戳,在不同的时区显示的结果是不一样的。反过来也一样,相同的字符串,在不同的时区解释下,会得到不同的时间戳。

我们来看一下整个mysqldump的结果。在文件头部,可以看到

/*!40103 SET TIME_ZONE='+00:00' */; 字样,说明mysqldump在默认情况下,是按’+00:00’(中时区).

mysql客户端的默认值呢:

mysql> select @@time_zone;

+-------------+

| @@time_zone |

+-------------+

| SYSTEM      |

+-------------+

 

这个SYSTEM表示MySQL取操作系统的默认时区,因此是东8区。如果我们设置为与mysqldump相同时区,

mysql> set time_zone='+00:00';  

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from tb;

+---------------------+

| t                   |

+---------------------+

| 2012-12-13 16:42:45 |

+---------------------+

1 row in set (0.00 sec)

就跟我们上面看到的全表导出的结果一样了。

也就是说,这个问题是因为mysqldump强行设置了时区为中时区造成的。

 

解决1

mysqldump的代码中我们看到,可以用 --tz-utc=0 参数去掉前面的设置时区的动作。这样用的也是默认时区。

mysqldump  --tz-utc=0 -Srun/mysql.sock -uroot   test tb   --where='c="2012-12-14 00:42:45"'  |grep INSERT

INSERT INTO `tb` VALUES ('2012-12-14 00:42:45');

 

可以看到,这个貌似就是我们要的结果,导出的结果也很合理。

 

进一步

如果这个这么好,为什么mysqldump的开发者不把—tz-utc=0作为默认行为呢?也就是说哦这样做有什么风险?

实际上是因为要防止跨时区导数据。假设你把中国一个机器上的数据导入到美国的一个mysqld(想起@plinux 说的b2b就有这种情况),若不显式地设置一个时区,在导入时就会出错了。因为都用系统默认的时区,相同的字符串值会得到不同的时间戳。如我们前面说的, 时间戳是以整型方式存储的。

 

解决2

所以上面的--tz-utc=0存在风险。当然如果你确定源和目标系统时区没变,是ok的。我们讨论看看有没有更保险的方法。

既然是时间戳是保险的,其实可以考虑,用时间戳来做where条件。

mysql> select unix_timestamp(c) from tb;

+-------------------+

| unix_timestamp(c) |

+-------------------+

|        1355416965 |

+-------------------+

 

按照表里的这个值,我们的dump命令改成

mysqldump   -Srun/mysql.sock -uroot   test tb   --where=' unix_timestamp(c)=1355416965' | grep INSERT

INSERT INTO `tb` VALUES ('2012-12-13 16:42:45');

这次对了,而且与是否使用 --tz-utc=0  无关,都能得到结果,区别只是显示问题。

 

不过对MySQL比较熟悉的同学就知道,这个写法还是存在一个问题:用不上索引,因为我们在字段上做了unix_timestamp这个操作。有时候我们在这种表上为了导出方便有一个索引专门建在timestamp字段上。

 

因此想到用逆函数

mysqldump   -Srun/mysql.sock -uroot   test tb   --where='c= from_unixtime(1355416965)'  | grep INSERT         

INSERT INTO `tb` VALUES ('2012-12-13 16:42:45');

 

5
0
分享到:
评论
4 楼 lidayu_up 2013-04-11  
虽然dump出来时间不一样,但是导进去的时候,又变回来了
3 楼 andyjackson 2012-12-17  
mark. mysql运维工作需要注意滴
2 楼 xieye 2012-12-15  
更好的办法就是不用这个类型
1 楼 zhoujy 2012-12-14  
非常好,一直都没注意这个事情。

相关推荐

    MySQL 5.6 中的 TIMESTAMP 和 explicit_defaults_for_timestamp 参数

    此外,MySQL允许在一个表中最多定义两个自动更新的`TIMESTAMP`字段,其中一个可以设置为`CURRENT_TIMESTAMP`作为默认值,另一个可以设置为`ON UPDATE CURRENT_TIMESTAMP`,这样在插入新行或更新行时,这两个字段都会...

    mysql之TIMESTAMP(时间戳)用法详解

    例如,如果你有一个TIMESTAMP(6)的列,HOUR()函数将无法正确获取小时部分,除非你的TIMESTAMP列定义为至少TIMESTAMP(10)。 在实际应用中,选择合适的TIMESTAMP行为和显示尺寸取决于你的需求。如果需要在每次更新时...

    Mysql中的Datetime和Timestamp比较

    MySQL数据库系统中,时间数据类型是用来存储日期和时间值的,其中包括`DATE`、`DATETIME`和`TIMESTAMP`。这些类型在某些方面相似,但在其他方面却有着明显的区别。下面将详细介绍`DATETIME`和`TIMESTAMP`的比较,并...

    mysql时间类型对应的java类型1

    MySQL数据库提供了多种时间类型来处理日期和时间数据: 1. **DATE**:这个类型仅存储日期,格式为'YYYY-MM-DD',不包含时间部分。在Java中,对应的类型是`java.sql.Date`,它表示没有时间部分的日期。 2. **TIME**...

    MySQL错误TIMESTAMP column with CURRENT_TIMESTAMP的解决方法

    在MySQL 5.5版本之前,存在一个限制,即每个表中最多只能有一个`TIMESTAMP`列具有`CURRENT_TIMESTAMP`作为默认值或自动更新值。这意味着你不能在一个列中设置`DEFAULT CURRENT_TIMESTAMP`同时在另一个列中设置`ON ...

    spirng-boot 的时间类型(date、datetime、timestamp)的全局配置

    以下是一个简单的实体类示例: ```java import java.time.LocalDate; import java.time.LocalDateTime; public class Event { private Long id; private LocalDate date; private LocalDateTime dateTime; //...

    python自动备份mysql数据库,并删除七天前文件

    这个示例提供了一个基本框架,实际应用中可能需要添加错误处理、日志记录、更复杂的定时机制(如使用`cron`或Python的`schedule`库)等。这样的自动化流程可以显著减轻运维人员的工作负担,确保数据库的定期备份,并...

    MySQL中datetime和timestamp的区别及使用详解

    在MySQL数据库中,datetime和timestamp是两种常用的日期和时间数据类型,它们虽然都可以用来存储日期和时间信息,但在使用和处理上存在一些显著的区别。本文将深入探讨这两种数据类型的差异以及如何在实际应用中选择...

    MySQL 5.6 中 TIMESTAMP 的变化分析

    2. 表中的第一个TIMESTAMP列,如果未声明NULL、DEFAULT或ON UPDATE属性,会自动获得DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性。这使得该列在插入新行时默认设置为当前时间,并在后续更新时自动...

    在MySql中获取当前系统当前时间的函数和TIMESTAMP列类型使用说明

    在这个例子中,当我们插入一行数据并将`date1` 和 `data2` 列的值设置为`NULL`时,MySQL将自动用当前的日期和时间填充这些列。 通过以上介绍可以看出,在MySQL中,获取当前系统的日期和时间以及使用`TIMESTAMP` 列...

    mysql 数据类型TIMESTAMP

    在mysql中timestamp数据类型是一个比较特殊的数据类型,他可以自动在你不使用程序更新情况下只要你更新了记录timestamp会自动更新时间 通常表中会有一个Create date 创建日期的字段,其它数据库均有默认值的选项。...

    MySQL中文参考手册

    10. **视图**:视图是虚拟表,基于一个或多个表的查询结果。学习如何创建和使用视图,以及其在数据抽象和权限控制中的应用。 此外,手册还会涵盖MySQL的最新版本特性,如窗口函数、JSON支持和分区表等,以及如何...

    mysql的timestamp类型字段为'0000-00-00 00:00:00'导致mybatis映射时报错解决方法

    在MySQL中,`TIMESTAMP`字段允许最小值'1970-01-01 00:00:01'和最大值'2038-01-19 03:14:07',但'0000-00-00 00:00:00'是作为一个特殊的无效日期值存在。当你试图插入一个非有效日期或者不指定日期时,某些情况下,...

    python timestamp和datetime之间转换详解

    2. **Datetime**:是一个包含了日期和时间信息的数据类型,通常用于表示具体的日期和时间点。在 Python 中,`datetime` 模块提供了 `datetime` 类来处理日期和时间对象。 #### 二、字符串日期时间转换成时间戳 在...

    MYSQL教程02 MYSQL教程02 MYSQL教程02

    MySQL是一个开源、免费的关系型数据库管理系统,广泛应用于Web应用、数据分析等领域,其高效、稳定和易于维护的特点使其深受开发者喜爱。 首先,我们从基础开始,了解什么是数据库。数据库是存储和管理数据的系统,...

    MySql 5.1 参考手册.chm

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    解析mysql中UNIX_TIMESTAMP()函数与php中time()函数的区别

    首先,MySQL的UNIX_TIMESTAMP()函数是一个内置的时间和日期函数,它能够将日期或时间转换为自1970年1月1日00:00:00 GMT以来的秒数。如果函数没有参数调用,它会返回当前的Unix时间戳。如果提供了一个日期或时间参数...

    mysql的日期和时间函数

    mysql的日期和时间函数 这里是一个使用日期函数的例子。下面的查询选择所有 date_col 值在最后 30 天内的记录。 mysql> SELECT something FROM tbl_name WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) ...

Global site tag (gtag.js) - Google Analytics