MySQL中以数值类型存储IP地址

前言

  数据库中存储IP地址的时候,推荐使用整数存储而不是字符串。一般来说, 在保证正确性的前提下,尽量使用最小的数据类型来存储和展示数据;小的数据类型一般比大的更快,因为小的数据类型占用的磁盘空间,内存和cup缓存都相对小,需要的cpu处理也要相对少; 这个原则很重要,设计的时候不要低估待存储数据的数据范围。另外,转换之后,还便于使用范围查询(BETWEEN...AND),且效率更高。

  对于转换来说,MySQL提供了相关的函数来把字符串格式的IP转换成整数INET_ATON,以及把整数格式的IP转换成字符串的INET_NTOA。如下所示:

mysql> select inet_aton('192.168.0.1');
+--------------------------+
| inet_aton('192.168.0.1') |
+--------------------------+
|               3232235521 |
+--------------------------+
1 row in set (0.00 sec)

mysql> select inet_ntoa(3232235521);
+-----------------------+
| inet_ntoa(3232235521) |
+-----------------------+
| 192.168.0.1           |
+-----------------------+
1 row in set (0.00 sec)

对于IPv6来说,使用VARBINARY可获得相同的好处,同时MySQL也提供了转换函数INET6_ATONINET6_NTOA

IPv4地址和int类型数字互转

package com.hoss.ext.authentication;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * IPv4地址和int类型数字互转
 *
 * @author Wiener
 * @date 2021/4/29
 */
public class SaveIp {

    public static void main(String[] args) {
        String ip = "127.0.0.1";
        String ip33 = "172.16.24.33";
        String ip13 = "172.16.10.13";
        String ip89 = "111.112.113.114";
        intToIp(ipToInt(ip89));
    }

    /**
     * (Ip转Integer)
     * 方法名:ipToInt
     *
     * @throws
     * @since 1.0.0
     */
    public static int ipToInt(String ip) {
        if (!isIPv4Address(ip)) {
            throw new RuntimeException("Invalid ip address");
        }
        String[] ips = ip.split("\\.");
        int ipInt = 0;
        //因为每个位置最大255,刚好在2进制里表示8位
        for (String ip4 : ips) {
            Integer ip4a = Integer.parseInt(ip4);
            //这里应该用+也可以,但是位运算更快
            ipInt = (ipInt << 8) | ip4a;
        }
        System.out.println(ipInt);

        return ipInt;
    }

    /**
     * 判断是否为ipv4地址
     *
     * @param ipv4Addr
     * @return true 是ipv4地址
     */
    private static boolean isIPv4Address(String ipv4Addr) {
        // 0-255的数字
        String lower = "(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])";
        String regex = lower + "(\\." + lower + "){3}";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(ipv4Addr);
        return matcher.matches();
    }

    /**
     * (Integer转IP)
     * 方法名:intToIp
     *
     * @param ip数字
     * @return String
     */
    public static String intToIp(int ip) {
        //思路很简单,每8位拿一次,就是对应位的IP
        StringBuilder sb = new StringBuilder();
        for (int i = 3; i >= 0; i--) {
            int ipa = (ip >> (8 * i)) & (0xff);
            sb.append(ipa + ".");
        }
        sb.delete(sb.length() - 1, sb.length());
        System.out.println("数字转IP:" + sb);
        return sb.toString();
    }

}

Reference

posted @ 2021-04-30 17:37  楼兰胡杨  阅读(612)  评论(0编辑  收藏  举报