我用不小心用 mysql 的int(11) 存了 手机号,数据都有问题,有办法恢复么?
PHPz
PHPz 2017-04-17 11:11:03
[MySQL讨论组]

我用不小心用 mysql 的int(11) 存了用户的手机号,结果里面存的数据都是 10 位的,而且也不是单纯的被截断了一位, 比如手机号 18345231102 会被转成 4294967295 有办法恢复么,急。。。。。

问题补充: 1.数据库的存的手机号是类似这样的 511129633 437709550 947221024 1544096837 2770221786 3052396450 985251741 2147791994 1663290693 3067028521 842826454 2382976437 1811997122 2128974539 694514931 1816715878 876431887 737421250 1107794384 847325325

2.我问了下运维,是开了binlog 的,然后我跟他们要了一份。把里面所有的用户填手机号的sql的都找了出来,但是神奇的是sql里的手机号跟数据库里的是一样的,难道binlog里的sql是溢出之后的?

PHPz
PHPz

学习是最好的投资!

全部回复(6)
天蓬老师

沒辦法了,int的範圍是-2147483648~2147483647,而unsigned int也就是無符號整形的就是其兩倍0~4294967295。

你的數據超出了,計算機就自動按maxinteger來算了。舉個簡單點的比喻——U盤塞滿了,再塞不進了,但是你當時沒發現,到後來發現的時候已經沒用了。

除非你有當時存手機號的MYSQL腳本這類外界的記錄或者是LOG,想從本身恢復是不可能了。

天蓬老师

有开bin-log吗?

PHP中文网

根据MySQL源码里的处理逻辑,如果某个数字大于该字段的最大值(或小于最小值),则解析的时候返回的是最大值(或最小值),所以仅从数字本身是无法恢复的。但是如果你的MySQL服务开启了LOG,那么就有可能恢复。

以下是MySQL的整数解析代码Field_num::get_int(),来自 sql/field.cc +1130

/*
  Conver a string to an integer then check bounds.

  SYNOPSIS
    Field_num::get_int
    cs            Character set
    from          String to convert
    len           Length of the string
    rnd           OUT longlong value
    unsigned_max  max unsigned value
    signed_min    min signed value
    signed_max    max signed value

  DESCRIPTION
    The function calls strntoull10rnd() to get an integer value then
    check bounds and errors returned. In case of any error a warning
    is raised.

  RETURN
    0   ok
    1   error
*/

bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
                        longlong *rnd, ulonglong unsigned_max, 
                        longlong signed_min, longlong signed_max)
{
  char *end;
  int error;

  *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len,
                                            unsigned_flag, &end,
                                            &error);
  if (unsigned_flag)
  {

    if (((ulonglong) *rnd > unsigned_max) && (*rnd= (longlong) unsigned_max) ||
        error == MY_ERRNO_ERANGE)
    {
      goto out_of_range;
    }
  }
  else
  {
    if (*rnd < signed_min)
    {
      *rnd= signed_min;
      goto out_of_range;
    }
    else if (*rnd > signed_max)
    {
      *rnd= signed_max;
      goto out_of_range;
    }
  }
  if (table->in_use->count_cuted_fields &&
      check_int(cs, from, len, end, error))
    return 1;
  return 0;

out_of_range:
  set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
  return 1;
}
迷茫

应该找不回来,就算能找回也不能保证是正确的

怪我咯

如果是默认开的binlog,mysql默认是基于语句的binlog 也就是保存了完整的语句,可以通过binlog恢复

巴扎黑

虽然 Po 主很悲剧,但是这是一个好问题,也引出了两个好答案。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号