mysql中如何修改字段的enum枚举类型值
1:背景描述mysql数据库中有如下的表结构,需要关注的是status字段的类型,此次需求为想要将这个字段的枚举值中的error变更为initialize_failedmysql> desc servers;+-------------------+--------------------------------------------------------+------+-----+--
1:背景描述
mysql数据库中有如下的表结构,需要关注的是status字段的类型,此次需求为想要将这个字段的枚举值中的error变更为initialize_failed
mysql> desc servers;
+-------------------+--------------------------------------------------------+------+-----+--------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------------------------------------------------+------+-----+--------------+-------+
| id | varchar(36) | NO | PRI | NULL | |
| name | varchar(36) | NO | | NULL | |
| gw_id | varchar(36) | NO | | NULL | |
| client_ip_pool | varchar(36) | NO | | NULL | |
| eip_id | varchar(36) | YES | | NULL | |
| proto | enum('UDP') | YES | | UDP | |
| status | enum('initializing','initialized','error') | YES | | initializing | |
| port | int(11) | NO | | NULL | |
| compress | tinyint(1) | YES | | NULL | |
| url | varchar(512) | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
| deleted_at | datetime | YES | | NULL | |
| deleted | bigint(20) | YES | | NULL | |
+-------------------+--------------------------------------------------------+------+-----+--------------+-------+
2:问题分析
首先需要提及的是,该表所依赖的项目已经运行过一段时间,即该表中已有一定的数据,可能status属性中已有error的数据存在,毕竟突然将某个字段的类型进行变更,一定也意味着项目中的源代码也在这里做了相应的改变,db中该表该字段出现error的数据也是可以理解的。因此安全起见,查询了这个表中的status字段的状态
mysql> select * from vpn_servers where initialize_status = 'error' limit 2;
Empty set (0.00 sec)
mysql> select distinct initialize_status from vpn_servers;
+-------------------+
| initialize_status |
+-------------------+
| initialized |
| initializing |
+-------------------+
2 rows in set (0.00 sec)
很惊喜,这个表中这个字段的值没有error的,那么接下来就有两种方式修改这个字段的枚举值了。
(1)直接修改表结构,重定义这个枚举类型值。
(2)修改表结构,新增这个枚举类型值initialize_failed,然后再将原有的error的值修改为initialize_failed,最后再重定义枚举值删除error
注意:如果这个表中是有这个error的数据,那么一定要走方法2,如果想走方法1,那么权衡好是生产环境还是测试环境,是否可以安全地删除这个status具有error的数据,该表是否和其他表有外键?级联删除关联?,如果想要删除,一定要通过api来删除,以免在db,缓存中留下脏数据。
3:问题解决
方法(1):因为本例中我发现了这个表中没有关于这个status字段有error的数据,所以图方便,可以直接修改
alter table servers modify `status` enum ('initializing','initialized','initialize_failed') default 'initializing';
**方法(2)**开始讲方法2前,试想下下面情况,如果该表中有error的数据,如下所示
MariaDB [test_using]> select * from servers where status = 'error' \G
*************************** 1. row ***************************
id: 12345
name: test
gw_id: 11111
client_ip_pool: NULL
eip_id: 22222
status: error
1 row in set (0.00 sec)
此时在status字段有error数据的情况下,再想像方法1那样直接更改会出现不可预知的问题,比如本例中,直接更改,导致原来的error的数据直接变为空(不是null),此时如果是生产环境,一个小小的螺丝钉的问题就有可能会产生一系列重大事故。
MariaDB [test_using]> alter table servers modify `status` enum ('initializing','initialized','initialize_failed') default 'initializing';
Query OK, 1 row affected, 1 warning (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 1
MariaDB [test_using]> select * from servers where status = 'error' \G
Empty set (0.00 sec)
MariaDB [test_using]>
MariaDB [test_using]>
MariaDB [test_using]> select * from servers \G
*************************** 1. row ***************************
id: 12345
name: test
gw_id: 11111
client_ip_pool: NULL
eip_id: 22222
status:
1 row in set (0.00 sec)
因此,正确且安全的方式如下
先对该表enum字段新增一个新的类型值
alter table servers modify `status` enum ('initializing','initialized','error','initialize_failed') default 'initializing';
接着update该表,将原有的要被替换掉的类型值error的数据变为新的类型值’initialize_failed’
update servers set status = 'initialize_failed' where status = 'error';
最后,再次变更表中status的enum的类型值,去掉error
alter table servers modify `status` enum ('initializing','initialized','initialize_failed') default 'initializing';
查询数据后
MariaDB [test_using]> select * from servers \G
*************************** 1. row ***************************
id: 12345
name: test
gw_id: 11111
client_ip_pool: NULL
eip_id: 22222
status: initialize_failed
1 row in set (0.00 sec)
4:后记
其实还有一种最不推荐的方法,那就是删表重建,适用于线下环境,或者表中数据都是垃圾数据的情形下,删掉也不心疼。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)