数据库中存储IP地址使用哪种数据类型好

1,270 阅读1分钟

终于周四了,今天咱们聊下数据库存储IP地址时的数据类型选择问题。

在高性能mysql一书中,作者建议:当存储IPv4的地址时,使用32位的无符号整数(UNSIGNED INT)来存储,而不是使用字符串。

优点

  • 节省空间,不管是数据存储空间还是索引存储空间
  • 便于使用范围查询(between and),效率也更高

与字符串类型比较

在使用字符串存储ip地址时,字符串长度在7-15之间,所以可以使用varchar(15)来存储。同时,mysql在存储变长字符串时,还需要一个额外的字节来存储字符串的长度。而使用无符号整数存储时,只需要4个字节。

缺点

  • 不便于阅读
  • 需要手动转换 对于转换来讲,mysql 提供了把字符串格式转成整数的函数INET_ATON,以及把整数转换为字符串格式的函数INET_NTOA
select inet_aton('192.168.0.1');
3232235521

select inet_ntoa('3232235521');
192.168.0.1

IPv6使用VARBINARY可以获得相同的好处同时MySQL也提供了相应的转换函数,即INET6_ATONINET6_NTOA

转换IPv4与字符串可以放在应用层。

java实现

public class IpLongUtils {
    /**
     * 把字符串IP转换成long
     *
     * @param ipStr 字符串IP
     * @return IP对应的long值
     */
    public static long ip2Long(String ipStr) {
        String[] ip = ipStr.split("\\.");
        return (Long.valueOf(ip[0]) << 24) + (Long.valueOf(ip[1]) << 16)
                + (Long.valueOf(ip[2]) << 8) + Long.valueOf(ip[3]);
    }

    /**
     * 把IP的long值转换成字符串
     *
     * @param ipLong IP的long值
     * @return long值对应的字符串
     */
    public static String long2Ip(long ipLong) {
        StringBuilder ip = new StringBuilder();
        ip.append(ipLong >>> 24).append(".");
        ip.append((ipLong >>> 16) & 0xFF).append(".");
        ip.append((ipLong >>> 8) & 0xFF).append(".");
        ip.append(ipLong & 0xFF);
        return ip.toString();
    }

    public static void main(String[] args) {
        System.out.println(ip2Long("192.168.0.1"));
        System.out.println(long2Ip(3232235521L));
        System.out.println(ip2Long("10.0.0.1"));
    }
}

输出为:

3232235521

192.168.0.1

167772161