1 package main 2 3 import ( 4 "database/sql" 5 "fmt" 6 _ "github.com/go-sql-driver/mysql" 7 ) 8 9 // 定義一個全局對象db 10 var db *sql.DB 11 //定義結構體 12 type User struct { 13 Id int 14 Name string 15 Age int 16 } 17 18 //初始化數據庫 19 func InitDB() (err error) { 20 //連接數據庫 21 dsn := "root:root@tcp(127.0.0.1:3306)/db3" 22 db, err = sql.Open("mysql", dsn) 23 //錯誤處理 24 if err != nil { 25 return err 26 } 27 //檢驗dsn是否正確 28 err = db.Ping() 29 if err != nil { 30 return err 31 } 32 return nil 33 } 34 35 //數據庫單行查詢 36 func queryRowDemo() { 37 //創建User對象 38 var u User 39 //sql語句 40 sqlStr := "select * from user where id=?" 41 //調用QueryRow方法返回查詢的一行,后邊調用的scan方法是將查詢出來的行放入指定的參數中 42 err := db.QueryRow(sqlStr, 1).Scan(&u.Id, &u.Name, &u.Age) 43 if err != nil { 44 fmt.Println(err) 45 return 46 } 47 fmt.Println(u.Id, u.Name, u.Age) 48 } 49 50 //查詢多行 51 /* 52 查詢多行和查詢單行的不同之處是調用方法query並返回多行 53 然后通過for循環調用scan方法吧每一行循環遍歷出來 54 */ 55 func queryDemo() { 56 //sql語句 57 sqlStr := "select * from user" 58 //調用方法 59 rows, err := db.Query(sqlStr) 60 //錯誤處理 61 if err != nil { 62 fmt.Println(err) 63 } 64 //關閉rows釋放持有的數據庫鏈接 65 defer rows.Close() 66 //使用for循環進行結果的讀取 67 for rows.Next() { 68 var u User 69 err := rows.Scan(&u.Id, &u.Name, &u.Age) 70 if err != nil { 71 fmt.Println(err) 72 } 73 fmt.Printf("id:%d name:%s age:%d\n", u.Id, u.Name, u.Age) 74 } 75 } 76 77 //插入數據 78 func InsertDemo() { 79 //sql語句 80 sqlStr := "insert into user(name,age) value(?,?)" 81 //Exec執行一次命令(包括查詢、刪除、更新、插入等),返回的Result是對已執行的SQL命令的總結。參數args表示query中的占位參數 82 ret, err := db.Exec(sqlStr, "趙六", 30) 83 if err != nil { 84 fmt.Println(err) 85 return 86 } 87 fmt.Println(ret) 88 // 新插入數據的id是theID 89 theID, err := ret.LastInsertId() 90 if err != nil { 91 fmt.Printf("get lastinsert ID failed, err:%v\n", err) 92 return 93 } 94 fmt.Printf("insert success, the id is %d.\n", theID) 95 } 96 97 //更新數據 98 func UpdateDemo() { 99 sqlStr := "update user set age=? where id =?" 100 ret, err := db.Exec(sqlStr, 39, 3) 101 if err != nil { 102 fmt.Printf("update failed, err:%v\n", err) 103 return 104 } 105 n, err := ret.RowsAffected() // 操作影響的行數 106 if err != nil { 107 fmt.Printf("get RowsAffected failed, err:%v\n", err) 108 return 109 } 110 fmt.Printf("update success, affected rows:%d\n", n) 111 } 112 113 //刪除數據 114 func DeleteDemo() { 115 sqlStr := "delete from user where id=?" 116 ret, err := db.Exec(sqlStr, 4) 117 if err != nil { 118 fmt.Println(err) 119 return 120 } 121 n, err := ret.RowsAffected() 122 if err != nil { 123 fmt.Printf("get RowsAffected failed, err:%v\n", err) 124 return 125 } 126 fmt.Printf("delete success, affected rows:%d\n", n) 127 128 } 129 func main() { 130 //調用初始化函數 131 err := InitDB() 132 if err != nil { 133 fmt.Println(err) 134 } 135 //調用函數 136 //queryRowDemo() 137 //queryDemo() 138 //InsertDemo() 139 //UpdateDemo() 140 //DeleteDemo() 141 }
sql預處理:
優化MySQL服務器重復執行SQL的方法,可以提升服務器性能,提前讓服務器編譯,一次編譯多次執行,節省后續編譯的成本。
避免SQL注入問題。
查詢的sql預處理代碼:
1 //預處理 2 func prepareSql() { 3 var u User 4 sqlStr := "select * from user" 5 stmt, err := db.Prepare(sqlStr) 6 if err != nil { 7 fmt.Println(err) 8 return 9 } 10 defer stmt.Close() 11 rows, err := stmt.Query() 12 if err != nil { 13 fmt.Println(err) 14 return 15 } 16 defer rows.Close() 17 for rows.Next() { 18 err := rows.Scan(&u.Id, &u.Name, &u.Age) 19 if err != nil { 20 fmt.Println(err) 21 return 22 } 23 fmt.Println(u.Id, u.Name, u.Age) 24 } 25 }
事務:
比如,我們去銀行轉賬,操作可以分為下面兩個環節:(1)從第一個賬戶划出款項。
(2)將款項存入第二個賬戶。
在這個過程中,兩個環節是關聯的。第一個賬戶划出款項必須保證正確的存入第二個賬戶,如果第二個環節沒有完成,整個的過程都應該取消,否則就會發生丟失款項的問題。整個交易過程,可以看作是一個事物,成功則全部成功,失敗則需要全部撤消,這樣可以避免當操作的中間環節出現問題時,產生數據不一致的問題。
事務的特性:
原子性 | 一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。 |
一致性 | 在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及后續數據庫可以自發性地完成預定的工作。 |
隔離性 | 數據庫允許多個並發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務並發執行時由於交叉執行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。 |
持久性 | 事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。 |
舉例:
1 func transactionDemo() { 2 //事務分為 開始事務 提交事務和回滾事務 3 //開始事務 當開始一個事務后需要用事務進行操作 4 tx, err := db.Begin() 5 //出錯了 如果有錯誤就需要進行事務的回滾 6 if err != nil { 7 if tx != nil { 8 tx.Rollback() 9 } 10 return 11 } 12 13 sqlStr := "update user set age=100 where id=?" 14 _, err = tx.Exec(sqlStr, 1) 15 if err != nil { 16 fmt.Println(err) 17 tx.Rollback() 18 return 19 } 20 21 sqlStr1 := "update user set age=101 where id=?" 22 _, err = tx.Exec(sqlStr1, 2) 23 if err != nil { 24 fmt.Println(err) 25 tx.Rollback() 26 return 27 } 28 //事務提交 29 err=tx.Commit() 30 if err!=nil{ 31 tx.Rollback() 32 return 33 } 34 35 }