# Go IP如何储存进去MYSQL
---
```javascript=
要了解IP是如何储存的进去MYSQL数据库的,需要从这个几个方面下手:
1. IP与数值类型的转换
2. IP地址跟MYSQL的数据存储之间的关系
3. MYSQL数据如何处理IP类型
```
## 1. IP与数值类型的转换
:::success
```go=
package main
import (
"fmt"
"net"
"reflect"
"github.com/thinkeridea/go-extend/exnet"
)
func main() {
ip := "192.168.1.1"
n, _ := exnet.IPString2Long(ip) // 以数值类型存储进去数据库
s, _ := exnet.Long2IPString(n) // 以ip字符串形式读取数据
// 192*256*256*256+168*256*256+1*256+1 = 3232235777
fmt.Println(n, s == ip) // 3232235777 true
Ip1 := net.ParseIP(ip) // 会得到一个16字节的byte,主要为了兼容ipv6
n, _ = exnet.IP2Long(Ip1) // 以数值类型存储进去数据库
Ip2, _ := exnet.Long2IP(n) // 以ip字符串形式读取数据
fmt.Println(Ip1) // 192.168.1.1
fmt.Println(n) // 3232235777
fmt.Println(Ip1) // 192.168.1.1
fmt.Println(n, reflect.DeepEqual(Ip1[12:], Ip2)) // 3232235777 true
}
// ParseIP,IPString2Long,Long2IPString,IP2Long,Long2IP 源码函数
// ParseIP 把ip字符串转为IP类型
type IP []byte
func ParseIP(s string) IP {
for i := 0; i < len(s); i++ {
switch s[i] {
case '.': // ipv4地址
return parseIPv4(s)
case ':': // ipv6地址
return parseIPv6(s)
}
}
return nil
}
// IPString2Long 把ip字符串转为数值
func IPString2Long(ip string) (uint, error) {
b := net.ParseIP(ip).To4()
if b == nil {
return 0, errors.New("invalid ipv4 format")
}
return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}
// Long2IPString 把数值转为ip字符串
func Long2IPString(i uint) (string, error) {
if i > math.MaxUint32 {
return "", errors.New("beyond the scope of ipv4")
}
ip := make(net.IP, net.IPv4len)
ip[0] = byte(i >> 24)
ip[1] = byte(i >> 16)
ip[2] = byte(i >> 8)
ip[3] = byte(i)
return ip.String(), nil
}
// IP2Long 把net.IP转为数值
func IP2Long(ip net.IP) (uint, error) {
b := ip.To4()
if b == nil {
return 0, errors.New("invalid ipv4 format")
}
return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}
// Long2IP 把数值转为net.IP
func Long2IP(i uint) (net.IP, error) {
if i > math.MaxUint32 {
return nil, errors.New("beyond the scope of ipv4")
}
ip := make(net.IP, net.IPv4len)
ip[0] = byte(i >> 24)
ip[1] = byte(i >> 16)
ip[2] = byte(i >> 8)
ip[3] = byte(i)
return ip, nil
}
```
:::
## 2. IP地址跟MYSQL的数据存储之间的关系
```javascript=
ipv4大家都知道是从0.0.0.0到255.255.255.255;
然而使用IP2Long函数转换后并不是我们想象中的0到4294967295,
而是0.0.0.0-127.255.255.255,转换后为0到2147483647;
128.0.0.0-255.255.255.255转换后为-2147483647到-1;
IP地址转换成int类型正好是int的有符号取整范围,为什么呢?
MySQL中int类型占4个字节,每个字节占8位 // 0-255 0-127, -127--1
总大小为(2^8-1)*(2^8-1)*(2^8-1)*(2^8-1)=255*255*255*255,是不是和IP地址的范围很类似;
```
## 3. IP地址跟MYSQL的数据存储之间的关系
- 简要说明
```javascript=
在Mysql中并没有提供针对IP地址存储的数据格式
在开发中我们可以选择使用char、varchar、int来存储
根据mysql字段类型选择的规则:
1. 字段类型定义使用最合适(最小)、最简单的数据类型,优先选择使用int类型来存储
2. int在逻辑运算上也要比char、varchar更快
```
- int类型存储IP地址
```javascript=
在Mysql中提供了两个函数,用来把IP地址与数字类型的相互转化
这种算法(inet_aton())其实借用了国际上对各国IP地址的区分中使用的ip number。
A.B.C.D 的ip number是:
A * 256^3 + B * 256^2 + C * 256 + D
```
```javascript=
inet_aton():把IP地址转化为数字
```
```sql=
mysql> select inet_aton('192.168.1.1');
+------------------------------+
| inet_aton('192.168.1.1') |
+------------------------------+
| 3232235777|
+------------------------------+
1 row in set (0.00 sec)
```
```javascript=
inet_ntoa():把数字转化成IP地址
```
```sql=
mysql> select inet_ntoa(4294967295);
+-----------------------+
| inet_ntoa(3232235777) |
+-----------------------+
| 192.168.1.1 |
+-----------------------+
1 row in set (0.00 sec)
```
```javascript=
当前很多应用都适用字符串char(15)来存储IP地址(占用16个字节);
利用inet_aton()和inet_ntoa()函数,来存储IP地址;
适用unsigned int 就可以满足需求,不需要使用bigint,只需要4个字节;
也节省存储空间,同时效率也高很多。
```
```javascript=
IPV4地址由4个组数字组成,每组数字之间以.分隔,每组数字的取值范围是0-255。
[0-99,100-199,200-249,250-255]
IPV4必须满足以下四条规则:
1、任何一个1位或2位数字,即0-99; 正则\d{1,2}
2、任何一个以1开头的3位数字,即100-199; 正则1\d{2}
3、任何一个以2开头、第2位数字是0-4之间的3位数字,即200-249; 正则2[0-4]\d
4、任何一个以25开头,第3位数字在0-5之间的3位数字,即250-255。 正则25[0-5]
组合起来,就得到一个匹配0-255数字的正则表达式了:(\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5])
IPV4由四组这样的数字组成,中间由.隔开,或者说由三组数字和字符.和一组数字组成,所以匹配IPV4的正则表达式如下:
(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))
```
- 比较有价值的正则表达式(别人的博文)
https://blog.csdn.net/dangjun625/article/details/83428354?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
###### tags: `Golang` `mysql` `ip`