Go sqlx的增删改查+事务

sqlx的增删改查

数据库设计

在这里插入图片描述
表test1
在这里插入图片描述
表test2
在这里插入图片描述

插入操作(Scrypt算法给用户密码加密)

Scrypt算法主要用于区块链,虽然难以破解,但是计算时间长,影响性能

package main

import (
	"database/sql"
	"encoding/base64"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"golang.org/x/crypto/scrypt"
	"log"
	"math/rand"
	"time"
)

type Person struct {
	UserId   int            `db:"user_id" json:"user_id"`
	Username string         `db:"username" json:"username"`
	Password sql.NullString `db:"password" json:"password"`
	Email    sql.NullString `db:"email" json:"email"`
	Age      sql.NullInt64  `db:"age" json:"age"`
}

type Place struct {
	Country string         `db:"country"`
	City    sql.NullString `db:"city"`
	Code    int            `db:"code"`
}

var Db *sqlx.DB

// int类型转化为sql.NullInt64
func IntToNullInt64(a int) sql.NullInt64 {
	return sql.NullInt64{Int64: int64(a), Valid: true}
}
// string类型转化为sql.NullString
func StringToNullString(a string) sql.NullString {
	return sql.NullString{String: a, Valid: true}
}

// 将密码加密,即使用户输入的密码相同,最后数据库中的密码依旧不同

func ScryptPwd(password string) string {
	const KeyLen = 10
	rand.Seed(time.Now().UnixNano())
	salt := make([]byte, 8)
	// 随机数使盐也不同,这样即便某些用户的密码相同,他们编码的密码也不同
	salt = []byte{byte(rand.Intn(2000)), byte(rand.Intn(3003)), byte(rand.Intn(3000)), byte(rand.Intn(5000)), byte(rand.Intn(5000)), byte(rand.Intn(200))}
	HashPwd, err := scrypt.Key([]byte(password), salt, 16384, 8, 1, KeyLen)
	if err != nil {
		log.Fatal(err)
	}
	fpwd := base64.StdEncoding.EncodeToString(HashPwd)
	return fpwd
}

func init() {
	db, err := sqlx.Open("mysql", "root:061118@tcp(127.0.0.1:3306)/person")
	if err != nil {
		//fmt.Println("open mysql failed,", err)
		//continue
		panic(err)
	}
	Db = db
}

func main() {
	defer Db.Close()

	// 往表test1中插入数据
	// 法一:Exec插入数据
	r1, err := Db.Exec("insert into test1(username,password,email) values (?,?,?)", "tom", ScryptPwd("154"), "222@qq.com")
	if err != nil {
		fmt.Println("exec failds,", err)
		return
	}
	id_1, err := r1.LastInsertId()
	if err != nil {
		fmt.Println("exec faild", err)
		return
	}
	fmt.Println("insert success", id_1)

	// 法二:NameExec插入数据
	person := Person{
		Username: "jerry",
		Password: StringToNullString(ScryptPwd("154")),
		Email:    StringToNullString("455@163.com"),
		Age:      IntToNullInt64(20),
	}
	r2, err := Db.NamedExec("insert into test1(username,password,email,age)values (:username,:password,:email,:age)", person)
	if err != nil {
		fmt.Println("name exec err:", err)
		return
	}
	id_2, err := r2.LastInsertId()
	if err != nil {
		fmt.Println("exec faild", err)
		return
	}
	fmt.Println("insert success", id_2)

	// 往表test2中插入数据

	// 法一:Exec插入数据
	row1, err := Db.Exec("insert into test2(country,city,code) values (?,?,?)", "china", "xian", 2)
	if err != nil {
		fmt.Println("exec failds,", err)
		return
	}
	id_3, err := row1.LastInsertId()
	if err != nil {
		fmt.Println("exec faild", err)
		return
	}
	fmt.Println("id_1 success:", id_3)

	// 法二:NameExec插入数据
	place1 := Place{
		Country: "usa",
		City:    StringToNullString("newyork"),
		Code:    21,
	}
	row2, err2 := Db.NamedExec("insert into test2(country,city,code)values (:country,:city,:code)", place1)
	if err2 != nil {
		fmt.Println("nameexec err:", err2)
		return
	}
	id_4, err := row2.LastInsertId()
	if err != nil {
		fmt.Println("NameExec faild:", err)
		return
	}
	fmt.Println("insert success:", id_4)
}

在这里插入图片描述
在这里插入图片描述

删除操作

package main

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)


var Db *sqlx.DB

func init() {
	db, err := sqlx.Open("mysql", "root:061118@tcp(127.0.0.1:3306)/person")
	if err != nil {
		fmt.Println("database open err:", err)
		return
	}
	Db = db
}

func main() {
	defer Db.Close()
	res, err := Db.Exec("delete from test1 where user_id = ?", 168)
	if err != nil {
		fmt.Println("delete faild:", err)
		return
	}
	row, err := res.RowsAffected()
	if err != nil {
		fmt.Println("rows faild:", err)
	}
	fmt.Println("delete success:", row)
}

更新操作

package main

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

var Db *sqlx.DB

func init() {
	db, err := sqlx.Open("mysql", "root:061118@tcp(127.0.0.1:3306)/person")
	if err != nil {
		fmt.Println("database open err:", err)
		return
	}
	Db = db
}

func main() {
	defer Db.Close()
	r, err := Db.Exec("update test1 set username = ? where user_id = ?", "李四", 163)
	if err != nil {
		fmt.Println("update err :", err)
		return
	}
	row, err := r.RowsAffected()
	if err != nil {
		fmt.Println("rows faild:", err)
	}
	fmt.Println("update success:", row)
}

查询操作

Select和Query用于查询多条记录
Get和QueryRow用于查询单条记录

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

type Person struct {
	UserId   int            `db:"user_id" json:"user_id"`
	Username string         `db:"username" json:"username"`
	Password sql.NullString `db:"password" json:"password"`
	Email    sql.NullString `db:"email" json:"email"`
	Age      sql.NullInt32  `db:"age" json:"age"`
}

var Db *sqlx.DB

func init() {
	db, err := sqlx.Open("mysql", "root:061118@tcp(127.0.0.1:3306)/person")
	if err != nil {
		fmt.Println("open mysql failed,", err)
		return
		//panic(err)
	}
	Db = db
}

func main() {
	defer Db.Close()
	var p []Person
	// Select用于多行查询 Select的第一个值是一个切片
	err := Db.Select(&p, "select username,password,email,age from test1 where username = ?", "jerry")
	if err != nil {
		fmt.Println("select failds,", err)
		return
	}
	fmt.Println("select success", p)

	// Get用于单行查询
	var p1 Person
	err1 := Db.Get(&p1, "select username,password,age from test1 where user_id = ?", 164)
	if err != nil {
		fmt.Println("get err:", err1)
		return
	}
	fmt.Println("get success", p1)

	// Query方法用于查询多条记录
	rows, err := Db.Query("select username,password,email,age from test1 where user_id > 2")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer rows.Close()
	for rows.Next() {
		var (
			username string
			password sql.NullString
			email    sql.NullString
			age      sql.NullInt32
		)
		if err := rows.Scan(&username, &password, &email, &age); err != nil {
			fmt.Println(err)
			return
		}
		fmt.Println(username, password, email, age)
	}
	rows.Close()
	// Err返回迭代期间遇到的错误(如果有)。Err可在显式或隐式关闭后调用
	if err = rows.Err(); err != nil {
		fmt.Println("err...", err)
		return
	}
	fmt.Println("----------")
	//QueryRow方法用于查询单条记录
	var city sql.NullString
	//var country string
	row := Db.QueryRow("select city from test2 where code = 1")
	err3 := row.Scan(&city)
	if err3 != nil {
		fmt.Println("scan err:", err3)
		return
	}
	fmt.Println(city)

	// 含有空值的查询
	var email sql.NullString
	var username string
	var password sql.NullString
	var age sql.NullInt32
	newrow := Db.QueryRow("select email,username,password,age from test1 where user_id = 167")
	err4 := newrow.Scan(&email, &username, &password, &age)
	if err4 != nil {
		fmt.Println("scan err...:", err4)
		return
	}
	fmt.Println(email, username, password, age)
}

事务

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

type Person struct {
	UserId   int            `db:"user_id" json:"user_id"`
	Username string         `db:"username" json:"username"`
	Password sql.NullString `db:"password" json:"password"`
	Email    sql.NullString `db:"email" json:"email"`
	Age      sql.NullInt64  `db:"age" json:"age"`
}

type GRPCPersonOption func(*Person)

func StringToNullString(a string) sql.NullString {
	return sql.NullString{String: a, Valid: true}
}

func NewPerson(opts ...GRPCPersonOption) *Person {
	entry := &Person{
		Email: StringToNullString("111@163.com"),
	}
	for i := range opts {
		opts[i](entry)
	}
	return entry
}

func withEmail(email sql.NullString) GRPCPersonOption {
	return func(entry *Person) {
		entry.Email = email
	}
}

var Db *sqlx.DB

func init() {
	db, err := sqlx.Open("mysql", "root:061118@tcp(127.0.0.1:3306)/person")
	if err != nil {
		fmt.Println("database open err:", err)
		return
	}
	Db = db
}

func main() {
	conn, err := Db.Beginx()
	if err != nil {
		fmt.Println("begin err:", err)
		return
	}
	// NamedExec插入
	p := NewPerson(withEmail(StringToNullString("7889@qq.com")))
	p.Username = "KANSH2"
	p.Password = StringToNullString("123987")
	result1, err1 := conn.NamedExec("insert into test1(username,password,email) values (:username,:password,:email)", p)
	if err1 != nil {
		fmt.Println("exec faild..", err1)
		conn.Rollback()
		return
	}
	id_1, err := result1.LastInsertId()
	if err != nil {
		fmt.Println("exec failed, ", err)
		conn.Rollback()
		return
	}
	fmt.Println("insert success:", id_1)

	// Exec插入
	result2, err2 := conn.Exec("insert into test1(username,password,email) values (?,?,?)", "西门吹雪", "1234", "455@163.com")
	if err2 != nil {
		fmt.Println("insert err:", err)
		conn.Rollback()
		return
	}
	id_2, err := result2.LastInsertId()
	if err != nil {
		fmt.Println("exec failed, ", err)
		conn.Rollback()
		return
	}
	fmt.Println("insert success:", id_2)

	conn.Commit()
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Go中使用SQLx进行数据库查询,首先需要定义一个结构体来表示数据库表的数据模型。这个结构体应该包含与表中每个列对应的字段,并且每个字段应该有一个`db`标签,表示该字段在数据库中的列名。 例如,假设我们有一个名为`users`的表,其中包含`id`、`name`和`email`列。我们可以定义一个名为`User`的结构体来表示这个表的数据模型,如下所示: ```go type User struct { ID int `db:"id"` Name string `db:"name"` Email string `db:"email"` } ``` 接下来,我们可以使用`sqlx.DB.Query`或`sqlx.DB.Queryx`方法执行查询,并将结果映射到我们定义的结构体中。例如,如果我们想查询`users`表中所有用户的数据,可以使用以下代码: ```go // 创建一个 SQLx DB 连接 db, err := sqlx.Connect("mysql", "user:password@tcp(localhost:3306)/mydb") if err != nil { log.Fatalln(err) } // 查询所有用户 var users []User err = db.Select(&users, "SELECT id, name, email FROM users") if err != nil { log.Fatalln(err) } // 打印查询结果 for _, user := range users { fmt.Printf("ID: %d, Name: %s, Email: %s\n", user.ID, user.Name, user.Email) } ``` 在上面的代码中,我们使用`sqlx.DB.Select`方法执行查询,并将结果映射到`users`变量中。`&users`表示将查询结果映射到一个`User`结构体的切片中。查询结果的每一行都会映射到一个`User`结构体中,并添加到`users`切片中。最后,我们遍历`users`切片,并打印每个用户的ID、姓名和电子邮件。 要注意的是,我们在查询中只选择了`id`、`name`和`email`列,因此只有这些列的数据会映射到`User`结构体中。如果查询中选择了其他列,但在`User`结构体中没有对应的字段,则这些列的数据将被忽略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值