package hotime import ( "database/sql" "encoding/json" "errors" "os" "reflect" "strings" ) type HoTimeDB struct { *sql.DB contextBase CacheIns Type string DBCached bool LastQuery string LastData []interface{} ConnectFunc func(err ...*Error) *sql.DB LastErr Error limit Slice Tx *sql.Tx //事务对象 } //设置数据库配置连接 func (this *HoTimeDB) SetConnect(connect func(err ...*Error) *sql.DB, err ...*Error) { this.ConnectFunc = connect this.InitDb() } //事务,如果action返回true则执行成功;false则回滚 func (this *HoTimeDB) Action(action func(db HoTimeDB) bool) bool { db := HoTimeDB{DB: this.DB, CacheIns: this.CacheIns, DBCached: this.DBCached} tx, err := db.Begin() if err != nil { this.LastErr.SetError(err) return false } db.Tx = tx result := action(db) if !result { db.Tx.Rollback() return result } db.Tx.Commit() return result } func (this *HoTimeDB) InitDb(err ...*Error) Error { if len(err) != 0 { this.LastErr = *(err[0]) } this.DB = this.ConnectFunc(&this.LastErr) if this.DB == nil { return this.LastErr } e := this.DB.Ping() this.LastErr.SetError(e) return this.LastErr } func (this *HoTimeDB) Page(page, pageRow int) *HoTimeDB { page = (page - 1) * pageRow if page < 0 { page = 1 } this.limit = Slice{page, pageRow} return this } func (this *HoTimeDB) PageSelect(table string, qu ...interface{}) []Map { if len(qu) == 1 { qu = append(qu, Map{"LIMIT": this.limit}) } if len(qu) == 2 { temp := qu[1].(Map) temp["LIMIT"] = this.limit qu[1] = temp } if len(qu) == 3 { temp := qu[2].(Map) temp["LIMIT"] = this.limit qu[2] = temp } //fmt.Println(qu) data := this.Select(table, qu...) return data } //数据库数据解析 func (this *HoTimeDB) Row(resl *sql.Rows) []Map { dest := make([]Map, 0) strs, _ := resl.Columns() for i := 0; resl.Next(); i++ { lis := make(Map, 0) a := make([]interface{}, len(strs)) b := make([]interface{}, len(a)) for j := 0; j < len(a); j++ { b[j] = &a[j] } resl.Scan(b...) for j := 0; j < len(a); j++ { if a[j] != nil && reflect.ValueOf(a[j]).Type().String() == "[]uint8" { lis[strs[j]] = string(a[j].([]byte)) } else { lis[strs[j]] = a[j] } } //防止int被误读为float64 jlis, e := json.Marshal(lis) if e != nil { this.LastErr.SetError(e) } else { lis.JsonToMap(string(jlis), &this.LastErr) } dest = append(dest, lis) } return dest } // ////code=0,1,2 0 backup all,1 backup data,2 backup ddl //func (this *HoTimeDB) Backup(path string, code int) { // var cmd *exec.Cmd // switch code { // case 0:cmd= exec.Command("mysqldump","-h"+ObjToStr(Config["dbHost"]), "-P"+ObjToStr(Config["dbPort"]),"-u"+ObjToStr(Config["dbUser"]), "-p"+ObjToStr(Config["dbPwd"]),ObjToStr(Config["dbName"])) // case 1:cmd= exec.Command("mysqldump","-h"+ObjToStr(Config["dbHost"]), "-P"+ObjToStr(Config["dbPort"]),"-u"+ObjToStr(Config["dbUser"]), "-p"+ObjToStr(Config["dbPwd"]), ObjToStr(Config["dbName"])) // case 2:cmd= exec.Command("mysqldump","--no-data","-h"+ObjToStr(Config["dbHost"]), "-P"+ObjToStr(Config["dbPort"]),"-u"+ObjToStr(Config["dbUser"]), "-p"+ObjToStr(Config["dbPwd"]),ObjToStr(Config["dbName"])) // } // // // // stdout, err := cmd.StdoutPipe() // if err != nil { // log.Println(err) // } // // if err := cmd.Start(); err != nil { // log.Println(err) // } // // bytes, err := ioutil.ReadAll(stdout) // if err != nil { // log.Println(err) // } // err = ioutil.WriteFile(path, bytes, 0644) // if err != nil { // panic(err) // } // return ; // // // //db := `` // //fmt.Println(db) // // // //tables := this.Query("show tables") // //lth := len(tables) // //if lth == 0 { // // return // //} // //for k, _ := range tables[0] { // // db = Substr(k, 10, len(k)) // //} // // // //fd, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) // //fd.Write([]byte("/*datetime " + time.Now().Format("2006-01-02 15:04:05") + " */ \r\n")) // //fd.Close() // // // //for i := 0; i < lth; i++ { // // tt := tables[i]["Tables_in_"+db].(string) // // this.backupSave(path, tt, code) // // debug.FreeOSMemory() // //} // //} func (this *HoTimeDB) backupSave(path string, tt string, code int) { fd, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) defer fd.Close() str := "\r\n" if code == 0 || code == 2 { str += this.backupDdl(tt) } if code == 0 || code == 1 { str += "insert into `" + tt + "`\r\n\r\n(" str += this.backupCol(tt) } fd.Write([]byte(str)) } func (this *HoTimeDB) backupDdl(tt string) string { data := this.Query("show create table " + tt) if len(data) == 0 { return "" } return ObjToStr(data[0]["Create Table"]) + ";\r\n\r\n" } func (this *HoTimeDB) backupCol(tt string) string { str := "" data := this.Select(tt, "*") lthData := len(data) if lthData == 0 { return str } lthCol := len(data[0]) col := make([]string, lthCol) tempLthData := 0 for k, _ := range data[0] { if tempLthData == lthCol-1 { str += "`" + k + "`)" } else { str += "`" + k + "`," } col[tempLthData] = k tempLthData++ } str += " values" for j := 0; j < lthData; j++ { for m := 0; m < lthCol; m++ { if m == 0 { str += "(" } v := "NULL" if data[j][col[m]] != nil { v = "'" + strings.Replace(ObjToStr(data[j][col[m]]), "'", `\'`, -1) + "'" } if m == lthCol-1 { str += v + ")" } else { str += v + "," } } if j == lthData-1 { str += ";\r\n\r\n" } else { str += ",\r\n\r\n" } } return str } func (this *HoTimeDB) md5(query string, args ...interface{}) string { strByte, _ := json.Marshal(args) str := Md5(query + ":" + string(strByte)) return str } func (this *HoTimeDB) Query(query string, args ...interface{}) []Map { //fmt.Println(query) var err error var resl *sql.Rows this.LastQuery = query this.LastData = args if this.DB == nil { err = errors.New("没有初始化数据库") this.LastErr.SetError(err) return nil } if this.Tx != nil { resl, err = this.Tx.Query(query, args...) } else { resl, err = this.DB.Query(query, args...) } this.LastErr.SetError(err) if err != nil { if err = this.DB.Ping(); err != nil { this.LastErr.SetError(err) this.InitDb() if this.LastErr.GetError() != nil { return nil } return this.Query(query, args...) } return nil } return this.Row(resl) } func (this *HoTimeDB) Exec(query string, args ...interface{}) (sql.Result, Error) { this.LastQuery = query this.LastData = args var e error var resl sql.Result if this.DB == nil { err := errors.New("没有初始化数据库") this.LastErr.SetError(err) return nil, this.LastErr } if this.Tx != nil { resl, e = this.Tx.Exec(query, args...) } else { resl, e = this.DB.Exec(query, args...) } this.LastErr.SetError(e) //判断是否连接断开了 if e != nil { if e = this.DB.Ping(); e != nil { this.LastErr.SetError(e) this.InitDb() if this.LastErr.GetError() != nil { return resl, this.LastErr } return this.Exec(query, args...) } } return resl, this.LastErr } //func (this *HoTimeDB)copy(data []Map)[]Map{ // if data==nil{ // return nil // } // // lth:=len(data) // // res:=make([]Map,lth) // // // for i:=0;i 0 { if reflect.ValueOf(qu[intQs]).Type().String() == "string" { query += " " + qu[intQs].(string) } else { for i := 0; i < len(qu[intQs].(Slice)); i++ { k := qu[intQs].(Slice)[i].(string) if strings.Contains(k, " AS ") { query += " " + k + " " } else { query += " `" + k + "` " } if i+1 != len(qu[intQs].(Slice)) { query = query + ", " } } } } else { query += " *" } query += " FROM " + table if join { for k, v := range qu[0].(Map) { switch Substr(k, 0, 3) { case "[>]": query += " LEFT JOIN " + Substr(k, 3, len(k)-3) + " ON " + v.(string) case "[<]": query += " RIGHT JOIN " + Substr(k, 3, len(k)-3) + " ON " + v.(string) } switch Substr(k, 0, 4) { case "[<>]": query += " FULL JOIN " + Substr(k, 4, len(k)-4) + " ON " + v.(string) case "[><]": query += " INNER JOIN " + Substr(k, 4, len(k)-4) + " ON " + v.(string) } } } if len(qu) > 1 { where = qu[intWhere].(Map) } temp, resWhere := this.where(where) query += temp qs = append(qs, resWhere...) md5 := this.md5(query, qs...) if this.DBCached && this.CacheIns != nil { //如果缓存有则从缓存取 cacheData := this.Cache(table + ":" + md5) if cacheData.Data != nil { return cacheData.ToMapArray() } } //无缓存则数据库取 res := this.Query(query, qs...) if res == nil { res = []Map{} } //缓存 if this.DBCached && this.CacheIns != nil { this.Cache(table+":"+md5, res) } return res } func (this *HoTimeDB) Get(table string, qu ...interface{}) Map { //fmt.Println(qu) if len(qu) == 1 { qu = append(qu, Map{"LIMIT": 1}) } if len(qu) == 2 { temp := qu[1].(Map) temp["LIMIT"] = 1 qu[1] = temp } if len(qu) == 3 { temp := qu[2].(Map) temp["LIMIT"] = 1 qu[2] = temp } //fmt.Println(qu) data := this.Select(table, qu...) if len(data) == 0 { return nil } return data[0] } /** ** 计数 */ func (this *HoTimeDB) Count(table string, qu ...interface{}) int { req := []interface{}{} if len(qu) == 2 { req = append(req, qu[0]) req = append(req, "COUNT(*)") req = append(req, qu[1]) } else { req = append(req, "COUNT(*)") req = append(req, qu...) } //req=append(req,qu...) data := this.Select(table, req...) //fmt.Println(data) if len(data) == 0 { return 0 } //res,_:=StrToInt(data[0]["COUNT(*)"].(string)) res := ObjToStr(data[0]["COUNT(*)"]) count, _ := StrToInt(res) return count } var condition = []string{"AND", "OR"} var vcond = []string{"GROUP", "ORDER", "LIMIT"} //where语句解析 func (this *HoTimeDB) where(data Map) (string, []interface{}) { where := "" res := make([]interface{}, 0) //AND OR判断 for k, v := range data { x := 0 for i := 0; i < len(condition); i++ { if condition[i] == k { tw, ts := this.cond(k, v.(Map)) where += tw res = append(res, ts...) break } x++ } y := 0 for j := 0; j < len(vcond); j++ { if vcond[j] == k { break } y++ } if x == len(condition) && y == len(vcond) { tv, vv := this.varCond(k, v) where += tv res = append(res, vv...) } } if len(where) != 0 { where = " WHERE " + where } //特殊字符 for j := 0; j < len(vcond); j++ { for k, v := range data { if vcond[j] == k { if k == "ORDER" { where += " " + k + " BY " //fmt.Println(reflect.ValueOf(v).Type()) //break } else if k == "GROUP" { where += " " + k + " BY " } else { where += " " + k } if reflect.ValueOf(v).Type().String() == "hotime.Slice" { for i := 0; i < len(v.(Slice)); i++ { where += " " + ObjToStr(v.(Slice)[i]) if len(v.(Slice)) != i+1 { where += "," } } } else { //fmt.Println(v) where += " " + ObjToStr(v) } break } } } return where, res } func (this *HoTimeDB) varCond(k string, v interface{}) (string, []interface{}) { where := "" res := make([]interface{}, 0) length := len(k) if length > 4 { def := false switch Substr(k, length-3, 3) { case "[>]": k = strings.Replace(k, "[>]", "", -1) where += "`" + k + "`>? " res = append(res, v) case "[<]": k = strings.Replace(k, "[<]", "", -1) where += "`" + k + "`=]": k = strings.Replace(k, "[>=]", "", -1) where += "`" + k + "`>=? " res = append(res, v) case "[<=]": k = strings.Replace(k, "[<=]", "", -1) where += "`" + k + "`<=? " res = append(res, v) case "[><]": k = strings.Replace(k, "[><]", "", -1) where += "`" + k + "` NOT BETWEEN ? AND ? " res = append(res, v.(Slice)[0]) res = append(res, v.(Slice)[1]) case "[<>]": k = strings.Replace(k, "[<>]", "", -1) where += "`" + k + "` BETWEEN ? AND ? " res = append(res, v.(Slice)[0]) res = append(res, v.(Slice)[1]) default: if reflect.ValueOf(v).Type().String() == "hotime.Slice" { where += "`" + k + "` IN (" res = append(res, (v.(Slice))...) if len(v.(Slice)) == 0 { where += ") " } else { for i := 0; i < len(v.(Slice)); i++ { if i+1 != len(v.(Slice)) { where += "?," } else { where += "?) " } //res=append(res,(v.(Slice))[i]) } } } else { where += "`" + k + "`=? " res = append(res, v) } } } } else if k == "[#]" { k = strings.Replace(k, "[#]", "", -1) where += " " + ObjToStr(v) + " " } else { //fmt.Println(reflect.ValueOf(v).Type().String()) if v == nil { where += "`" + k + "` IS NULL" } else if reflect.ValueOf(v).Type().String() == "hotime.Slice" { //fmt.Println(v) where += "`" + k + "` IN (" res = append(res, (v.(Slice))...) for i := 0; i < len(v.(Slice)); i++ { if i+1 != len(v.(Slice)) { where += "?," } else { where += "?) " } //res=append(res,(v.(Slice))[i]) } } else if reflect.ValueOf(v).Type().String() == "[]interface {}" { where += "`" + k + "` IN (" res = append(res, (v.([]interface{}))...) for i := 0; i < len(v.([]interface{})); i++ { if i+1 != len(v.([]interface{})) { where += "?," } else { where += "?) " } //res=append(res,(v.(Slice))[i]) } } else { where += "`" + k + "`=? " res = append(res, v) } } return where, res } // this.Db.Update("user",hotime.Map{"ustate":"1"},hotime.Map{"AND":hotime.Map{"OR":hotime.Map{"uid":4,"uname":"dasda"}},"ustate":1}) func (this *HoTimeDB) notIn(k string, v interface{}, where string, res []interface{}) (string, []interface{}) { //where:="" //fmt.Println(reflect.ValueOf(v).Type().String()) if v == nil { where += "`" + k + "` IS NOT NULL " } else if reflect.ValueOf(v).Type().String() == "hotime.Slice" { where += "`" + k + "` NOT IN (" res = append(res, (v.(Slice))...) for i := 0; i < len(v.(Slice)); i++ { if i+1 != len(v.(Slice)) { where += "?," } else { where += "?) " } //res=append(res,(v.(Slice))[i]) } } else if reflect.ValueOf(v).Type().String() == "[]interface {}" { where += "`" + k + "` NOT IN (" res = append(res, (v.([]interface{}))...) for i := 0; i < len(v.([]interface{})); i++ { if i+1 != len(v.([]interface{})) { where += "?," } else { where += "?) " } //res=append(res,(v.(Slice))[i]) } } else { where += "`" + k + "` !=? " res = append(res, v) } return where, res } func (this *HoTimeDB) cond(tag string, data Map) (string, []interface{}) { where := " " res := make([]interface{}, 0) lens := len(data) //fmt.Println(lens) for k, v := range data { x := 0 for i := 0; i < len(condition); i++ { if condition[i] == k { tw, ts := this.cond(k, v.(Map)) if lens--; lens <= 0 { //fmt.Println(lens) where += "(" + tw + ") " } else { where += "(" + tw + ") " + tag + " " } res = append(res, ts...) break } x++ } if x == len(condition) { tv, vv := this.varCond(k, v) res = append(res, vv...) if lens--; lens <= 0 { where += tv + "" } else { where += tv + " " + tag + " " } } } return where, res } //更新数据 func (this *HoTimeDB) Update(table string, data Map, where Map) int64 { query := "UPDATE " + table + " SET " //UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing' WHERE LastName = 'Wilson' qs := make([]interface{}, 0) tp := len(data) for k, v := range data { vstr := "?" if Substr(k, len(k)-3, 3) == "[#]" { k = strings.Replace(k, "[#]", "", -1) vstr = ObjToStr(v) } else { qs = append(qs, v) } query += "`" + k + "`=" + vstr + "" if tp--; tp != 0 { query += ", " } } temp, resWhere := this.where(where) //fmt.Println(resWhere) query += temp qs = append(qs, resWhere...) res, err := this.Exec(query, qs...) rows := int64(0) if err.GetError() == nil && res != nil { rows, _ = res.RowsAffected() } //如果更新成功,则删除缓存 if rows != 0 { if this.DBCached && this.CacheIns != nil { this.Cache(table+"*", nil) } } return rows } func (this *HoTimeDB) Delete(table string, data map[string]interface{}) int64 { query := "DELETE FROM " + table + " " temp, resWhere := this.where(data) query += temp res, err := this.Exec(query, resWhere...) rows := int64(0) if err.GetError() == nil && res != nil { rows, _ = res.RowsAffected() } //如果删除成功,删除对应缓存 if rows != 0 { if this.DBCached && this.CacheIns != nil { this.Cache(table+"*", nil) } } //return 0 return rows } //插入新数据 func (this *HoTimeDB) Insert(table string, data map[string]interface{}) int64 { values := make([]interface{}, 0) queryString := " (" valueString := " (" lens := len(data) tempLen := 0 for k, v := range data { tempLen++ values = append(values, v) if tempLen < lens { queryString += "`" + k + "`," valueString += "?," } else { queryString += "`" + k + "`) " valueString += "?);" } } query := "INSERT INTO " + table + queryString + "VALUES" + valueString res, err := this.Exec(query, values...) id := int64(0) if err.GetError() == nil && res != nil { id, this.LastErr.err = res.LastInsertId() } //如果插入成功,删除缓存 if id != 0 { if this.DBCached && this.CacheIns != nil { this.Cache(table+"*", nil) } } //fmt.Println(id) return id }