前言
- 在项目中可能会有一些需求或场景,比如在对接第三方需求时需要指定对方请求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))
使用int类型相对于字符串类型存储IP地址的优点:
- 1,能节省存储数据和索引数据所占用的空间
- 2,整型能更高效率使用范围匹配查询
有优点那就也有一些缺点:
- 书里也说明了使用小数点分隔的IP地址容易让人们阅读,所以整型IP地址可读性不如字符串格式好,取值还需要转义
在MySQL层转义IPv4地址:
- 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的四个地址,当然这仅仅在一些特定场景或需求里才适用的一种方式
- 虚心学习,共同进步 -_-