github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/04_database/demo2_mysql/op.go (about) 1 package demo2_mysql 2 3 import ( 4 "database/sql" 5 "fmt" 6 _ "github.com/go-sql-driver/mysql" 7 ) 8 9 func open() { 10 /* 11 连接数据库:func Open(driverName, dataSourceName string) (*DB, error) 12 Open打开一个dirverName指定的数据库,dataSourceName指定数据源, 13 一般包至少括数据库文件名和(可能的)连接信息。 14 15 driverName: 使用的驱动名. 这个名字其实就是数据库驱动注册到 database/sql 时所使用的名字. 16 dataSourceName: 数据库连接信息,这个连接包含了数据库的用户名, 密码, 数据库主机以及需要连接的数据库名等信息. 17 18 drvierName,"mysql" 19 dataSourceName,用户名:密码@协议(地址:端口)/数据库?参数=参数值 20 21 sql.Open并不会立即建立一个数据库的网络连接, 也不会对数据库链接参数的合法性做检验, 它仅仅是初始化一个sql.DB对象. 22 当真正进行第一次数据库查询操作时, 此时才会真正建立网络连接 23 24 sql.Open返回的sql.DB对象是协程并发安全的. 25 26 sql.DB的设计就是用来作为长连接使用的。不要频繁Open, Close。比较好的做法是,为每个不同的datastore建一个DB对象,保持这些对象Open。 27 如果需要短连接,那么把DB作为参数传入function,而不要在function中Open, Close。 28 */ 29 db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?charset=utf8") 30 fmt.Println("db_err : ", err) 31 // 立即验证连接,需要用Ping()方法 32 err = db.Ping() 33 fmt.Println("db : ", db) 34 fmt.Println("ping_err : ", err) 35 if err != nil { 36 fmt.Println("连接有误。。", err) 37 return 38 } 39 fmt.Println("连接成功。。") 40 db.Close() 41 } 42 43 func insert() { 44 // 打开数据库,相当于和数据库建立连接:db对象 45 db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?charset=utf8") 46 if err != nil { 47 fmt.Println(err) 48 return 49 } 50 51 // 插入语句 52 stmt, err := db.Prepare("INSERT INTO userinfo(username,departname,created) values(?,?,?)") 53 if err != nil { 54 fmt.Println("操作失败。。") 55 } 56 //补充完整sql语句,并执行 57 result, err := stmt.Exec("荣耀", "服务端", "2019-06-04") 58 if err != nil { 59 fmt.Println("插入数据失败。。", err) 60 } 61 lastInsertId, err := result.LastInsertId() 62 rowsAffected, err := result.RowsAffected() 63 fmt.Println("lastInsertId", lastInsertId) 64 fmt.Println("影响的行数:", rowsAffected) 65 66 //再次插入数据: 67 result, _ = stmt.Exec("ruby", "人事部", "2019-06-04") 68 count, _ := result.RowsAffected() 69 fmt.Println("影响的行数:", count) 70 71 // 关闭资源 72 stmt.Close() 73 db.Close() 74 } 75 76 func update() { 77 db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?charset=utf8") 78 if err != nil { 79 fmt.Println(err) 80 return 81 } 82 result, err := db.Exec("update userinfo SET username = ?, departname = ? WHERE uid = ?", "李维民", "公安局", 2) 83 if err != nil { 84 fmt.Println("更新数据失败。。", err) 85 } 86 lastInsertId, err := result.LastInsertId() 87 rowsAffected, err := result.RowsAffected() 88 fmt.Println("lastInsertId", lastInsertId) 89 fmt.Println("影响的行数:", rowsAffected) 90 91 db.Close() 92 } 93 94 /** 95 查询一条 96 */ 97 func queryOne() { 98 db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?charset=utf8") 99 if err != nil { 100 fmt.Println(err) 101 return 102 } 103 defer db.Close() 104 row := db.QueryRow("select uid,username,departname,created from userinfo where uid=?", 1) 105 var ( 106 uid int 107 username, departname, created string 108 ) 109 /* 110 row:Scan()-->将查询的结果从row取出 111 err对象 112 判断err是否为空, 113 为空,查询有结果,数据可以成功取出,如果是多条数据就是取第1条 114 不为空,没有数据,sql: no rows in result set 115 */ 116 err = row.Scan(&uid, &username, &departname, &created) 117 if err != nil { 118 fmt.Println("查询出错 -> ", err) 119 return 120 } 121 fmt.Println(uid, username, departname, created) 122 } 123 124 type User struct { 125 uid int 126 username string 127 departname string 128 created string 129 } 130 131 /* 132 查询多条 133 */ 134 func queryMulti() { 135 db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?charset=utf8") 136 if err != nil { 137 fmt.Println(err) 138 return 139 } 140 defer db.Close() 141 rows, err := db.Query("select uid,username,departname,created from userinfo where uid>?", 0) 142 if err != nil { 143 fmt.Println("查询出错 -> ", err) 144 return 145 } 146 defer rows.Close() 147 148 fmt.Println(rows.Columns()) //[uid username departname created] 149 150 //创建slice,存入struct, 151 var datas []User 152 // 操作结果集获取数据 153 for rows.Next() { 154 var ( 155 uid int 156 username, departname, created string 157 ) 158 if err := rows.Scan(&uid, &username, &departname, &created); err != nil { 159 fmt.Println("获取失败。。") 160 } 161 //每读取一行,创建一个user对象,存入datas2中 162 user := User{uid, username, departname, created} 163 datas = append(datas, user) 164 } 165 166 // 打印 167 for _, v := range datas { 168 fmt.Println(v) 169 } 170 } 171 172 func transaction() { 173 /* 174 事务: 175 4大特性:ACID 176 原子性: 177 一致性: 178 隔离性: 179 永久性: 180 */ 181 //ruby-->王二狗,2000元 182 183 db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_test?charset=utf8") 184 if err != nil { 185 fmt.Println(err) 186 return 187 } 188 defer db.Close() 189 190 //开启事务 191 tx, _ := db.Begin() 192 //提供一组sql操作 193 var aff1, aff2 int64 = 0, 0 194 result1, _ := tx.Exec("UPDATE account SET money=money-1 WHERE id=?", 1) 195 result2, _ := tx.Exec("UPDATE account SET money=money+1 WHERE id=?", 2) 196 //fmt.Println(result2) 197 if result1 != nil { 198 aff1, _ = result1.RowsAffected() 199 fmt.Println("aff1:", aff1) 200 } 201 if result2 != nil { 202 aff2, _ = result2.RowsAffected() 203 fmt.Println("aff2:", aff2) 204 } 205 206 /* 207 一个Tx会在整个生命周期中保存一个连接,然后在调用commit()或Rollback()的时候释放掉。 208 在调用这几个函数的时候必须十分小心,否则连接会一直被占用直到被垃圾回收 209 */ 210 if aff1 == 1 && aff2 == 1 { 211 //提交事务 212 tx.Commit() 213 fmt.Println("操作成功。。") 214 } else { 215 //回滚 216 tx.Rollback() 217 fmt.Println("操作失败。。。回滚。。") 218 } 219 } 220 221 func queryAllDb() { 222 db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/honor_ini?charset=utf8") 223 if err != nil { 224 fmt.Println(err) 225 return 226 } 227 // select table_name from information_schema.tables; 228 // show tables; 229 rows, err := db.Query("SHOW TABLES") 230 if err != nil { 231 fmt.Println("查询出错 -> ", err) 232 return 233 } 234 //读出查询出的列字段名 235 var tableNames []string 236 for rows.Next() { 237 var tname string 238 rows.Scan(&tname) 239 tableNames = append(tableNames, tname) 240 } 241 rows.Close() 242 for _, tname := range tableNames { 243 queryDataByTable(tname, db) 244 } 245 } 246 247 type TableData struct { 248 columns []string // 表头 249 data *[][]byte // 数据 250 } 251 252 type Ts struct { 253 ColumnName string 254 Value interface{} 255 } 256 257 func queryDataByTable(tname string, db *sql.DB) { 258 rows, err := db.Query("select * from " + tname) 259 if err != nil { 260 fmt.Println(tname, "表查询出错 -> ", err.Error()) 261 return 262 } 263 defer rows.Close() 264 265 //读出查询出的列字段名 266 cols, _ := rows.Columns() 267 //values是每个列的值,这里获取到byte里 268 values := make([][]byte, len(cols)) 269 //query.Scan的参数,因为每次查询出来的列是不定长的,用len(cols)定住当次查询的长度 270 scans := make([]interface{}, len(cols)) 271 //让每一行数据都填充到[][]byte里面 272 for i := range values { 273 scans[i] = &values[i] 274 } 275 //最后得到的map 276 results := make(map[int]map[string]string) 277 i := 0 278 for rows.Next() { //循环,让游标往下推 279 if err := rows.Scan(scans...); err != nil { //query.Scan查询出来的不定长值放到scans[i] = &values[i],也就是每行都放在values里 280 fmt.Println(err) 281 return 282 } 283 284 row := make(map[string]string) //每行数据 285 for k, v := range values { //每行数据是放在values里面,现在把它挪到row里 286 287 key := cols[k] 288 row[key] = string(v) 289 } 290 results[i] = row //装入结果集中 291 i++ 292 } 293 294 //查询出来的数组 295 for k, v := range results { 296 fmt.Println(k, v) 297 } 298 //fmt.Println(tname + " 表 查询完成") 299 } 300 301 //func formatToLua(data *TableData) string { 302 // var b strings.Builder 303 // b.WriteString("return {\n") 304 // // 拼接头部 305 // 306 // 307 // 308 // 309 // b.WriteString("}") 310 //}