github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgSql/Sync.go (about) 1 package kmgSql 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/bronze1man/kmg/kmgStrings" 8 //"github.com/bronze1man/kmg/kmgDebug" 9 ) 10 11 //读取数据库的表字段,不区分大小写(某些系统的mysql不区分大小写) 12 //写入数据库的表字段,区分大小写 13 type Table struct { 14 Name string 15 FieldList map[string]DbType 16 PrimaryKey string 17 UniqueKey [][]string 18 Null []string 19 } 20 21 type DbType string 22 23 const ( 24 DbTypeInt DbType = `int(11) DEFAULT 0` 25 DbTypeIntAutoIncrement DbType = `int(11) unsigned AUTO_INCREMENT` 26 DbTypeString DbType = `varchar(255) COLLATE utf8_bin DEFAULT ""` 27 DbTypeLongString DbType = `longtext COLLATE utf8_bin DEFAULT ""` 28 DbTypeFloat DbType = `float default 0` 29 DbTypeDatetime DbType = `datetime DEFAULT "0000-00-00 00:00:00"` 30 DbTypeBool DbType = `tinyint(4) DEFAULT 0` 31 DbTypeLongBlob DbType = `LONGBLOB` 32 ) 33 34 func (t DbType) GetMysqlFieldType() MysqlFieldType { 35 switch t { 36 case DbTypeInt: 37 return MysqlFieldType{ 38 DataType: MysqlDataTypeInt32, 39 Default: "0", 40 } 41 case DbTypeIntAutoIncrement: 42 return MysqlFieldType{ 43 DataType: MysqlDataTypeInt32, 44 IsUnsigned: true, 45 IsAutoIncrement: true, 46 } 47 case DbTypeString: 48 return MysqlFieldType{ 49 DataType: MysqlDataTypeVarchar, 50 Default: "", 51 CharacterSetName: "utf8", 52 CollationName: "utf8_bin", 53 StringLength: 255, 54 } 55 case DbTypeLongString: 56 return MysqlFieldType{ 57 DataType: MysqlDataTypeLongText, 58 Default: "", 59 CharacterSetName: "utf8", 60 CollationName: "utf8_bin", 61 } 62 case DbTypeFloat: 63 return MysqlFieldType{ 64 DataType: MysqlDataTypeFloat, 65 Default: "0", 66 } 67 case DbTypeDatetime: 68 return MysqlFieldType{ 69 DataType: MysqlDataTypeDateTime, 70 Default: "0000-00-00 00:00:00", 71 } 72 case DbTypeBool: 73 return MysqlFieldType{ 74 DataType: MysqlDataTypeInt8, 75 Default: "0", 76 } 77 case DbTypeLongBlob: 78 return MysqlFieldType{ 79 DataType: MysqlDataTypeLongBlob, 80 } 81 default: 82 panic(fmt.Errorf("Unsupport DbType %s", t)) 83 } 84 } 85 86 func MustSyncTable(tableConf Table) { 87 MustVerifyTableConfig(tableConf) 88 if MustIsTableExist(tableConf.Name) { 89 MustModifyTable(tableConf) 90 } else { 91 MustCreateTable(tableConf) 92 } 93 } 94 95 func MustForceSyncTable(tableConf Table) { 96 MustVerifyTableConfig(tableConf) 97 if MustIsTableExist(tableConf.Name) { 98 MustForceModifyTable(tableConf) 99 } else { 100 MustCreateTable(tableConf) 101 } 102 } 103 104 func MustIsTableExist(tableName string) bool { 105 ret := MustQueryOne("SHOW TABLE STATUS WHERE Name=?", tableName) 106 if len(ret) <= 0 { 107 return false 108 } else { 109 return true 110 } 111 } 112 113 func MustVerifyTableConfig(tableConf Table) { 114 fieldNameFieldMap := map[string]bool{} 115 for name := range tableConf.FieldList { 116 name := strings.ToLower(name) 117 if fieldNameFieldMap[name] { 118 panic(fmt.Errorf("[MustVerifyTableConfig] Table[%s] Field[%s] 两个字段名只有大小写不一致", 119 tableConf.Name, name)) 120 } 121 fieldNameFieldMap[name] = true 122 } 123 } 124 125 func MustCreateTable(tableConf Table) { 126 sql := "CREATE TABLE IF NOT EXISTS `" + tableConf.Name + "` \n(" 127 sqlItemList := []string{} 128 hasPrimaryKey := false 129 for fieldName, fieldType := range tableConf.FieldList { 130 if tableConf.PrimaryKey == fieldName { 131 hasPrimaryKey = true 132 //continue 133 } 134 sqlField := "`" + fieldName + "` " + string(fieldType) 135 if !kmgStrings.IsInSlice(tableConf.Null, fieldName) { 136 sqlField += " NOT NULL" 137 } 138 sqlItemList = append(sqlItemList, sqlField) 139 } 140 if tableConf.PrimaryKey != "" { 141 if !hasPrimaryKey { 142 panic(fmt.Sprintf(`tableConf.PrimaryKey[%s], 但是这个主键不在字段列表里面`, tableConf.PrimaryKey)) 143 } 144 //sqlItemList = append(sqlItemList, "`"+tableConf.PrimaryKey+"` int(11) unsigned AUTO_INCREMENT") 145 sqlItemList = append(sqlItemList, "PRIMARY KEY (`"+tableConf.PrimaryKey+"`)") 146 } 147 for _, group := range tableConf.UniqueKey { 148 uniqueSql := "UNIQUE INDEX (" 149 uniqueKeyList := []string{} 150 for _, key := range group { 151 uniqueKeyList = append(uniqueKeyList, "`"+key+"`") 152 } 153 uniqueSql += strings.Join(uniqueKeyList, ",") + ")" 154 sqlItemList = append(sqlItemList, uniqueSql) 155 } 156 sql += strings.Join(sqlItemList, ",\n") 157 sql += "\n) engine=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin" 158 MustExec(sql) 159 } 160 161 func MustModifyTable(tableConf Table) { 162 MysqlFieldTypeList := mustMysqlGetTableFieldTypeList(tableConf.Name) 163 dbFieldNameList := []string{} 164 for _, row := range MysqlFieldTypeList { 165 dbFieldNameList = append(dbFieldNameList, strings.ToLower(row.Name)) 166 } 167 for _, f1 := range dbFieldNameList { 168 found := false 169 for f2 := range tableConf.FieldList { 170 if strings.EqualFold(f2, f1) { 171 found = true 172 break 173 } 174 } 175 if !found { 176 fmt.Printf("[kmgSql.SyncTable] 数据库中包含多余字段 Table[%s] Field[%s]\n", tableConf.Name, f1) 177 } 178 } 179 for fieldName, fieldType := range tableConf.FieldList { 180 if !kmgStrings.IsInSlice(dbFieldNameList, strings.ToLower(fieldName)) { 181 MustAddNewField(tableConf, fieldName) 182 continue 183 } 184 for _, row := range MysqlFieldTypeList { 185 if row.Name == fieldName { 186 if !fieldType.GetMysqlFieldType().Equal(row.Type) { 187 fmt.Printf("[kmgSql.SyncTable] Table[%s] Field[%s] OldType[%s] NewType[%s] 数据库字段类型不一致\n", 188 tableConf.Name, fieldName, row.Type.String(), fieldType.GetMysqlFieldType().String()) 189 } 190 break 191 } 192 if strings.EqualFold(row.Name, fieldName) { 193 fmt.Printf("[kmgSql.SyncTable] Table[%s] OldField[%s] NewField[%s] 数据库字段大小写不一致\n", 194 tableConf.Name, fieldName, row.Name) 195 break 196 } 197 } 198 } 199 } 200 201 func MustForceModifyTable(tableConf Table) { 202 MysqlFieldTypeList := mustMysqlGetTableFieldTypeList(tableConf.Name) 203 dbFieldNameList := []string{} 204 for _, row := range MysqlFieldTypeList { 205 dbFieldNameList = append(dbFieldNameList, row.Name) 206 } 207 for _, f1 := range dbFieldNameList { 208 found := false 209 for f2 := range tableConf.FieldList { 210 if f2 == f1 { 211 found = true 212 break 213 } 214 } 215 if !found { 216 MustExec(fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN `%s`", tableConf.Name, f1)) 217 } 218 } 219 for fieldName, fieldType := range tableConf.FieldList { 220 if kmgStrings.IsInSlice(dbFieldNameList, fieldName) { 221 for _, row := range MysqlFieldTypeList { 222 if row.Name == fieldName { 223 if !fieldType.GetMysqlFieldType().Equal(row.Type) { 224 MustExec(fmt.Sprintf("ALTER TABLE `%s` CHANGE COLUMN `%s` `%s` %s NOT NULL", tableConf.Name, fieldName, fieldName, fieldType)) 225 } 226 break 227 } 228 } 229 continue 230 } 231 MustAddNewField(tableConf, fieldName) 232 } 233 } 234 235 func MustAddNewField(tableConf Table, newFieldName string) { 236 newFieldType := tableConf.FieldList[newFieldName] 237 sql := "ALTER TABLE `" + tableConf.Name + "` ADD `" + newFieldName + "` " + string(newFieldType) 238 if !kmgStrings.IsInSlice(tableConf.Null, newFieldName) { 239 sql += " NOT NULL" 240 } 241 MustExec(sql) 242 }