大家好,我是君哥。
虽然在拼夕夕上购物不多,但每年会有几次,每次都是看好商品后直接下单。不过这次有趣的是,订单显示已签收,我才发现买的东西被送到了老东家的前台,这个公司是我 5 年前的公司。
为什么下单会下错呢?我每次购物都是直接下单,因为已经很久没有变过默认收货地址了,这次是因为默认地址被修改了才配送错误。

1.默认地址
对每个电商用户来说,都会有几个收货地址,比如家庭住址、公司地址、老家地址、亲戚家地址等。但都会有一个默认地址,这个地址是最常用的一个收货地址,一般不会修改。
那我的默认地址为什么会被修改了呢?离开老东家已经 5 年了,我修改默认地址也不会改成这个地址啊。况且近两年我每次在夕夕上买东西都是直接下单。
那一个地址该怎样保存呢?拼夕夕上添加一个地址如下图:

一个地址的数据大概包括:省、市、区/县、姓名、电话、街道/详细地址,然后这些数据需要关联用户id。我们可以设计一张“用户收货地址”表:
CREATE TABLE`user_address` (
`id`BIGINT PRIMARY KEY AUTO_INCREMENT, -- 主键 ID
`user_id`BIGINTNOTNULL, -- 用户 ID
`user_name`VARCHAR(50) NOTNULL, -- 收货人姓名
`phone`VARCHAR(20) NOTNULL, -- 收货人电话
`country`VARCHAR(50) NOTNULL, -- 国家(支持国际化)
`province`VARCHAR(50) NOTNULL, -- 省
`city`VARCHAR(50) NOTNULL, -- 市
`district`VARCHAR(50) DEFAULTNULL, -- 区/县
`street`VARCHAR(255) NOTNULL, -- 街道/详细地址
`postal_code`VARCHAR(20) DEFAULTNULL, -- 邮编
`is_default`TINYINT(1) DEFAULT 0, -- 是否默认地址(0否,1是)
`create_date` DATETIME DEFAULTCURRENT_TIMESTAMP, --创建时间
`update_date` DATETIME ONUPDATECURRENT_TIMESTAMP,--更新时间
`is_deleted`TINYINT(1) DEFAULT 0 -- 逻辑删除
);
2.修改原因
上面用户收货地址表我们关联了 user_id, 同时用 is_default 字段用来标识是否是默认地址。这样只有当前用户在 app 上操作更改时才能修改这个地址。排除账号盗用、他人操作我的账户,那这个地址突然被修改可能是什么原因呢?
2.1 三方应用
有一种可能,手机上的三方应用同步信息到拼多多,导致了默认地址被修改。
2.2 数据库同步
数据库增加新节点,假设 MySQL 一主两从的集群架构,集群中一个节点数据正在同步,但请求已经发到新节点上,如下图:

加入 binlog 中最新的两条改动 SQL 如下:
--把老公司地址改为默认地址
UPDATE user_address SET is_default = 1 WHERE user_id = {userId} AND id = 1;
--把家庭住址改为默认地址
UPDATE user_address SET is_default = 1 WHERE user_id = {userId} AND id = 2;
这时如果刚刚同步完成第 1 条 SQL,第 2 条 SQL 还没有同步完成,用户请求过来了,这时取到的默认地址肯定是错误的。
2.3 历史数据
假如 user_address 表设计之初没有 is_default 这个字段,后来业务发展过程中,产品经理发现这个默认地址非常必要,就提出增加这个字段,而且是必输字段。作为程序员,历史数据怎样处理呢?
随便取表中一条记录作为客户的默认地址,这个设计最简单,但也很不负责任,选的地址可能并不是客户想要的默认地址; 取最新更新的一条记录作为客户的默认地址,这个刷数策略看似比较合理,但是也有问题。插入数据时 update_date 给的是系统时间,那 binlog 同步时,多条记录的 update_date 时间可能很接近,如果程序根据时间来判断只精确到秒级,这样多条记录更新时间一样 ,只能随机选择一条作为默认地址。
2.4 人为错误
程序员解决别的问题时,引入了 bug,把我的默认地址给修改了。
3.其他注意
设计客户收货地址时,还有其他几个点需要注意:
手机号、邮政编码合规校验; 地址省、市、区/县标准化; 详细地址合法性,验证这个地址是否真的存在; 订单表冗余地址信息,而不是关联 id,这样可以确保收货地址被修改后,订单信息的地址保持不变; 敏感数据加密,比如传输加密、日志脱敏,包括:姓名、住址、手机号等; 地址修改做权限控制,每个用户只能操作自己地址。
从用户体验方面看,可以考虑下面几点:
对于查询频率高的地址,做缓存,提高查询性能; 智能地址补全,用户输入体验更好; 增加地址标签,比如家、公司、父母家等。
4.总结
一个收货地址设计,表面看很简单,但要考虑安全、性能、可扩展和用户体验,还是有很多内容的。
感谢阅读,如果对你有帮助,请点赞和在看。欢迎加我微信:zhujinjun86。
号内回复 seata,下载《阿里分布式中间件Seata从入门到精通》
号内回复 beijing,下载我总结的北京上百家知名科技公司
号内回复 aqs,下载《40张图精通Java AQS》




