MySQL存储IP地址优化记录一下

前言

  • 在项目中可能会有一些需求或场景,比如在对接第三方需求时需要指定对方请求IP为白名单,用于白名单放行或黑名单过滤拦截,这时就需要持久化IP地址到本地数据库中,用于存储的数据库有多种,但大多数情况场景下用MySQL存储IP地址
  • 另外也可以用MongoDB存储IP地址,系统在单位时间内同一IP地址请求访问频率过多进行限制拦截可以使用Redis实现

MySQL存储IP信息:

  • 一般情况下在MySQL数据库中是常用VARCHAR(15)列的形式存储IP地址,IP最小长度7字符(0.0.0.1),最大长度15字符(255.255.255.255)
  • 在UFC-8编码下一个中文字符占3个字节,英文字符占2个字节,MySQL在使用变长字符串类型时还需要用一个字节保存其字符串长度,而MySQL中int类型固定占用4个字节。
    MySQL性能实验参考
  • 《高性能MySQL》 第三版中4.1.7小节里推荐使用无符号整数存储IP地址(无符号整数:MySQL中int类型有符号存储范围(-2147483648, 2147483647),无符号就是只存储正数其范围(0, 4294967295))

lADPDg7mRoclxhLNC9DND8A_4032_3024.jpg

使用int类型相对于字符串类型存储IP地址的优点:
  • 1,能节省存储数据和索引数据所占用的空间
  • 2,整型能更高效率使用范围匹配查询
有优点那就也有一些缺点:
  • 书里也说明了使用小数点分隔的IP地址容易让人们阅读,所以整型IP地址可读性不如字符串格式好,取值还需要转义
在MySQL层转义IPv4地址:

1629707668831_54777867-4A74-4121-B971-9F0024E7DA91.png

  • MySQL提供了INET_ATON()INET_NTOA() 函数,用于IPv4地址在整型和字符串之间的转化。
  • MySQL还提供了INET6_ATON()INET6_NTOA() 函数,用于IPv6地址在整型和字符串之间的转化。
在业务层进行计算转义IPv4地址:

00000000|00000000|00000000|00000000

  • IP地址在计算机中是用4字节保存的,每个字节用8位二进制,所以四个数一共需要32位数,所以只需要把字符串格式IP地址根据小数点拆分为4个数,分表保存在二进制中32位的4个段里
  • 比如IP地址的第一个数值向右移24位,第二个数值向右移16位,第三个数值向右移8位,第四个数值不移动,在将4个值相加就得到最终的整型IP地址
  • 解析整型IP地址只需把上述操作执行相反操作,分别使用位运算无符号向左移动24位,16位,8位。最后拼接结果即可。
/**
 * @Author: ZRH
 * @Date: 2021/8/23 14:08
 */
public final class IpLongUtils {

    /**
     * 把字符串IP转换成long
     *
     * @param ipStr 字符串IP
     * @return IP对应的long值
     */
    public static long ipToLong (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 longToIp (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(IpLongUtils.ipToLong("255.255.255.255"));
        System.out.println(IpLongUtils.longToIp(4294967295L));

        System.out.println(IpLongUtils.ipToLong("1.1.1.1"));
        System.out.println(IpLongUtils.longToIp(16843009L));
    }
}
--------------------------------------
打印结果:
4294967295
255.255.255.255
16843009
1.1.1.1

最后

  • 还有一些骚操作,比如使用四个字段分别保存IPv4的四个地址,当然这仅仅在一些特定场景或需求里才适用的一种方式
  • 虚心学习,共同进步 -_-
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值