需求:dev,test,release环境由于权限没有统一收管,很容易引起数据库表结构不一致情况;分享一个简单实用易上手的小工具;
mysql-schema-sync:
支持功能:
- 同步新表
- 同步字段 变动:新增、修改
- 同步索引 变动:新增、修改
- 支持预览(只对比不同步变动)
- 邮件通知变动结果
- 支持屏蔽更新表、字段、索引、外键
- 支持本地比线上额外多一些表、字段、索引、外键
安装:
go get -u github.com/hidu/mysql-schema-sync
参考 默认配置文件 config.json 配置同步源、目的地址。
修改邮件接收人 当运行失败或者有表结构变化的时候你可以收到邮件通知。
默认情况不会对多出的表、字段、索引、外键删除。若需要删除字段、索引、外键 可以使用 -drop
参数。
配置示例(config.json):
{ //source:同步源 "source":"test:test@(127.0.0.1:3306)/test_0", //dest:待同步的数据库 "dest":"test:test@(127.0.0.1:3306)/test_1", //alter_ignore: 同步时忽略的字段和索引 "alter_ignore":{ "tb1*":{ "column":["aaa","a*"], "index":["aa"], "foreign":[] } }, // tables: table to check schema,default is all.eg :["order_*","goods"] "tables":[], //有变动或者失败时,邮件接收人 "email":{ "send_mail":false, "smtp_host":"smtp.163.com:25", "from":"xxx@163.com", "password":"xxx", "to":"xxx@163.com" } }
json配置项说明
source: 数据库同步源
dest: 待同步的数据库
tables: 数组,配置需要同步的表,为空则是不限制,eg: ["goods","order_*"]
alter_ignore: 忽略修改的配置,表名为tableName,可以配置 column 和 index,支持通配符 *
email : 同步完成后发送邮件通知信息
直接运行
mysql-schema-sync -conf mydb_conf.json -sync
预览并生成变更sql
mysql-schema-sync -conf mydb_conf.json 2>/dev/null >db_alter.sql
使用shell调度
bash check.sh
每个json文件配置一个目的数据库,check.sh脚本会依次运行每份配置。 log存储在当前的log目录中。
自动定时运行
添加crontab 任务
30 * * * * cd /your/path/xxx/ && bash check.sh >/dev/null 2>&1
mysql-schema-sync [-conf] [-dest] [-source] [-sync] [-drop]
说明:
mysql-schema-sync -help
# mysql-schema-sync -help
-conf string
配置文件名称
-dest string
待同步的数据库 eg: test@(10.10.0.1:3306)/test_1
该项不为空时,忽略读入 -conf参数项
-drop
是否对本地多出的字段和索引进行删除 默认否
-source string
mysql 同步源,eg test@(127.0.0.1:3306)/test_0
-sync
是否将修改同步到数据库中去,默认否
-tables string
待检查同步的数据库表,为空则是全部
eg : product_base,order_*
参考:https://github.com/hidu/mysql-schema-sync 这种只适合于单个数据库的同步,对于不同实例上百个库的同步来说太过复杂;
上脚本:
(这脚本适用于不同实例之间表结构同步,user 需要有读写权限)
#!/usr/bin/env python #coding=utf-8 import os import json import pymysql import sys def get_m_json(filepath,key,value): key_ = key.split(".") key_length = len(key_) with open(filepath, ‘r‘) as f: json_data = json.load(f) i = 0 a = json_data while i < key_length : if i+1 == key_length : a[key_[i]] = "user:pass@("+mysources+":3306)/" + value i = i + 1 else : a = a[key_[i]] i = i + 1 f.close() return json_data def get_s_json(filepath,key,value): key_ = key.split(".") key_length = len(key_) with open(filepath, ‘r‘) as f: json_data = json.load(f) i = 0 a = json_data while i < key_length : if i+1 == key_length : a[key_[i]] = "usr:pass@("+mydest+":3306)/" + value i = i + 1 else : a = a[key_[i]] i = i + 1 f.close() return json_data def rewrite_json_file(filepath,json_data): with open(filepath, ‘w‘) as f: json.dump(json_data,f) f.close() if __name__ == ‘__main__‘: mysources = sys.argv[1] mydest = sys.argv[2] print (‘source:‘+mysources) print(‘dest:‘+mydest) json_path = "/root/go/src/github.com/hidu/mysql-schema-sync/config.json" mysqlsync="/usr/bin/mysql-schema-sync" print("jsonpath:",json_path) conn = pymysql.connect(host=mysources, port=3306, user="user", password="pass", database="information_schema") cursor = conn.cursor() sql = "select SCHEMA_NAME from SCHEMATA where SCHEMA_NAME not in (‘mysql‘,‘information_schema‘,‘performance_schema‘,‘test‘,‘sys‘);" cursor.execute(sql) m_dbs = cursor.fetchall() cursor.close() conn.close() print("sourcedbs:",m_dbs) conn = pymysql.connect(host=mydest, port=3306, user="user", password="pass", database="information_schema") cursor = conn.cursor() sql = "select SCHEMA_NAME from SCHEMATA where SCHEMA_NAME not in (‘mysql‘,‘information_schema‘,‘performance_schema‘,‘test‘,‘sys‘);" cursor.execute(sql) s_dbs = cursor.fetchall() cursor.close() conn.close() print("destdbs:",s_dbs) for m_db in m_dbs: for s_db in s_dbs: if m_db == s_db: m_json_data = get_m_json(json_path,"source",m_db[0]) rewrite_json_file(json_path,m_json_data) s_json_data = get_s_json(json_path,"dest",m_db[0]) rewrite_json_file(json_path,s_json_data) sync_cmd = str(mysqlsync)+‘ -conf ‘+json_path+‘ -sync 2>/dev/null >> ‘+mysources.split(‘.‘)[0]+‘_to_‘+mydest.split(‘.‘)[0]+‘_‘+m_db[0]+‘.sql‘ os.system(sync_cmd) sync_cmd1 = str(mysqlsync)+‘ -conf ‘+json_path+‘ -sync 2>/dev/null >>sync.log‘ print(sync_cmd1) os.system(sync_cmd1) break