Go语言入门心法(十):Go语言操作MYSQL(CRUD)|事务处理

news2024/12/27 15:43:44


Go语言入门心法(一): 基础语法

Go语言入门心法(二): 结构体

Go语言入门心法(三): 接口

Go语言入门心法(四): 异常体系

 Go语言入门心法(五): 函数

Go语言入门心法(六): HTTP面向客户端|服务端编程

Go语言入门心法(八): mysql驱动安装报错onnection failed

Go语言入门心法(九): 引入三方依赖

Go语言入门心法(十):Go语言操作MYSQL(CRUD)|事务处理




一: go连接mysql数据库


package main

import (
	"database/sql"
	"fmt"
	"log"
	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
)

/*
go语言连接mysql数据库操作:
*/
func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	if err != nil {
		fmt.Println("数据库连接异常: ", err)
	}

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	if err != nil {
		log.Fatal("数据库连接失败:", err)
	}
	log.Println("数据库连接成功: ", db.Stats())
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPMysqlToDatabaseLinkGrammar_go.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseLinkGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_OOPMysqlToDatabaseLinkGrammar_go.exe
2023/10/18 18:55:22 数据库连接成功:  {0 1 0 1 0 0s 0 0 0}

Process finished with the exit code 0

二: go连接mysql创建表


package main

/*
创建表:
*/

import (
	"database/sql"
	"fmt"
	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	if err != nil {
		log.Fatal(err)
		fmt.Println("数据库连接异常: ", err)
	}

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	if err != nil {
		log.Fatal("数据库连接失败:", err)
	}

	// 创建一张表
	createTable :=
		"CREATE TABLE `sys_go_dept` (" +
			"`deptid` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键'," +
			"`deptno` bigint(11) NOT NULL COMMENT '编码编号'," +
			"`dname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '部门名称'," +
			"`location` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '地点'," +
			"PRIMARY KEY (`deptid`)" +
			") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;"

	println(createTable)
	_, err = db.Exec(createTable)
	if err != nil {
		log.Fatal("创建表失败:", err)
	}
	log.Println("数据表创建成功")

}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseCreateTableGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database.exe
CREATE TABLE `sys_go_dept` (`deptid` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`deptno` bigint(11) NOT NULL COMMENT '编码编号',`dname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '部ocation` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '地点',PRIMARY KEY (`deptid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2023/10/18 18:52:40 数据表创建成功

Process finished with the exit code 0

三: go插入数据


package main

import (
	"database/sql"
	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	checkErr(err)

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	checkErr(err)

	log.Println("数据库连接成功! ")

	insertSql := "insert into `sys_go_dept` (deptno,dname,location)values (?,?,?) "
	rs, err := db.Exec(insertSql, 100000011, "销售总监", "北京市海淀区马连洼街道200号")
	checkErr(err)

	rowCount, err := rs.RowsAffected()
	checkErr(err)
	log.Printf("插入 %d 条数据", rowCount)
}

func checkErr(err error) {
	if err != nil {
		log.Fatal("系统异常: ", err.Error())
	}
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__1_.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseInsertGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__1_.exe
2023/10/18 19:47:03 数据库连接成功!
2023/10/18 19:47:03 插入 1 条数据

Process finished with the exit code 0

四: go修改数据


package main

import (
	"database/sql"
	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	updateCheckErr(err)

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	updateCheckErr(err)

	log.Println("数据库连接成功! ")

	updateSql := "update `sys_go_dept` set dname=? , location=? where deptno =? "
	rs, err := db.Exec(updateSql, "CFO(首席财务官)", "北京市朝阳区三里屯大街2000号", 100000011)
	updateCheckErr(err)

	rowCount, err := rs.RowsAffected()
	updateCheckErr(err)

	if rowCount > 0 {
		log.Println("更新成功")
	}

}

func updateCheckErr(err error) {
	if err != nil {
		log.Fatal("系统异常: ", err.Error())
	}
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__2_.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseQueryGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__2_.exe
2023/10/18 20:31:26 数据库连接成功!
2023/10/18 20:31:27 更新成功

Process finished with the exit code 0
 

五: go查询数据


package main

import (
	"database/sql"
	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	queryCheckErr(err)

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	queryCheckErr(err)

	log.Println("数据库连接成功! ")
	querySql := "select * from sys_go_dept where deptno = ?"

	rows, err := db.Query(querySql, 100000011)

	// 延迟执行
	defer rows.Close()

	for rows.Next() {
		user := User{}
		// 顺序需与数据库表的字段对应
		err := rows.Scan(&user.deptid, &user.deptno, &user.dname, &user.location)
		queryCheckErr(err)
		log.Println(user)
	}

}

type User struct {
	deptid   int64
	deptno   int64
	dname    string
	location string
}

func queryCheckErr(err error) {
	if err != nil {
		log.Fatal("系统异常: ", err.Error())
	}
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__2_.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseQueryGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__2_.exe
2023/10/18 20:54:42 数据库连接成功!
2023/10/18 20:54:42 {1 100000011 CFO(首席财务官) 北京市朝阳区三里屯大街2000号}
2023/10/18 20:54:42 {2 100000011 CFO(首席财务官) 北京市朝阳区三里屯大街2000号}
2023/10/18 20:54:42 {3 100000011 销售 北京市海淀区马连洼街道200号}

Process finished with the exit code 0
 


 

六: go删除数据

package main

import (
	"database/sql"
	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
	"log"
)

func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	deleteCheckErr(err)

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	deleteCheckErr(err)

	log.Println("数据库连接成功! ")

	deleteSql := "delete from `sys_go_dept` where deptid = ? "
	rs, err := db.Exec(deleteSql, 3)
	deleteCheckErr(err)

	rowCount, err := rs.RowsAffected()
	deleteCheckErr(err)

	if rowCount > 0 {
		log.Println("删除成功")
	}

}

func deleteCheckErr(err error) {
	if err != nil {
		log.Fatal("系统异常: ", err.Error())
	}
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__5_.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseDeleteGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__5_.exe
2023/10/18 21:02:56 数据库连接成功! 
2023/10/18 21:02:56 删除成功

Process finished with the exit code 0

七: go批量插入数据 


package main

import (
	"database/sql"
	"fmt"
	"log"

	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	batchInsertCheckErr(err)

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	batchInsertCheckErr(err)
	sqlStr, params := insertDataMap()
	log.Println("数据库连接成功! ")
	res, _ := db.Exec(sqlStr, params...) // params...: 解构
	id, _ := res.LastInsertId()
	fmt.Printf("lastId: %d insert success!", id)

}

// 插入多条数据
func insertDataMap() (string, []interface{}) {
	data := []map[string]string{
		{"deptno": "100000011", "dname": "CTO首席技术官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptno": "100000022", "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptno": "100000033", "dname": "CEO总经理", "location": "北京市昌平区龙泽苑街道200000"},
	}
	batchInsertSql := "insert into `sys_go_dept` (deptno,dname,location)values "
	var values []interface{}
	for index, row := range data {
		if index == len(data)-1 {
			batchInsertSql += "(?, ?, ?)"
		} else {
			batchInsertSql += "(?, ?, ?), "
		}
		values = append(values, row["deptno"], row["dname"], row["location"])
	}

	fmt.Println("batchInsertSql:", batchInsertSql)
	fmt.Println("values: ", values)
	return batchInsertSql, values
}

func batchInsertCheckErr(err error) {
	if err != nil {
		log.Fatal("系统异常: ", err.Error())
	}
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___2go_build_org_jd_data_org_jd_data_database__3_.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseBatchInsertGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___2go_build_org_jd_data_org_jd_data_database__3_.exe
batchInsertSql: insert into `sys_go_dept` (deptno,dname,location)values (?, ?, ?), (?, ?, ?), (?, ?, ?)
values:  [100000011 CTO首席技术官 北京市朝阳区三里屯大街20003号 100000022 CTO首席技术官 北京市海淀区马连洼30003路 100000033 CEO总经理 北京市昌平区龙泽苑街道200000]
2023/10/18 21:24:20 数据库连接成功!
lastId: 9 insert success!

Process finished with the exit code 0




Go操作Mysql驱动实现CRUD完整文档




八: go语言预处理批量插入


预处理认知升维: 

(1)sql包还提供了一种预编译的方式在执行SQL语句,通常在处理批量语句时会用到这种方式,

   这种方式比手动拼接字符串SQL语句高效,而且可以防止SQL注入攻击
(2) 使用Exec函数执行插入语句时,其中"?"表示参数占位符,使用这种方式参数可以有效防止出现SQL注入这类漏洞;

package main

/*
(1)sql包还提供了一种预编译的方式在执行SQL语句,通常在处理批量语句时会用到这种方式,

	这种方式比手动拼接字符串SQL语句高效,而且可以防止SQL注入攻击
(2) 使用Exec函数执行插入语句时,其中"?"表示参数占位符,使用这种方式参数可以有效防止出现SQL注入这类漏洞;
*/
import (
	"database/sql"
	"fmt"
	"log"

	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
)
func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	batchPrepareInsertCheckErr(err)

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	batchPrepareInsertCheckErr(err)
	batchInsertSql, params := initParamData()
	log.Println("数据库连接成功! ")
	stmt, err := db.Prepare(batchInsertSql) // 预处理SQL
	defer stmt.Close()
	batchPrepareInsertCheckErr(err)
	res,err := stmt.Exec(params...)
	batchPrepareInsertCheckErr(err)
	id, _ := res.LastInsertId()
	rowCount,err:=res.RowsAffected()
	batchPrepareInsertCheckErr(err)
	fmt.Printf("插入了 %d 条数据",rowCount)
	fmt.Printf("lastId: %d insert success!", id)

}

// 插入多条数据
func initParamData() (string, []interface{}) {
	data := []map[string] interface{}{
		{"deptid":0,"deptno": 100000011, "dname": "CPO首席产品官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptid":0,"deptno": 100000044, "dname": "COO首席营销官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":0,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市昌平区龙泽苑街道200000"},
		{"deptid":"0","deptno": 100000044, "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":nil,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市房山区龙泽苑街道200000"},
	}
	batchInsertSql := "insert into `sys_go_dept` values "
	var values []interface{}
	for index, row := range data {
		if index == len(data)-1 {
			batchInsertSql += "(?,?, ?, ?)"
		} else {
			batchInsertSql += "(?,?, ?, ?), "
		}
		values = append(values,row["deptid"], row["deptno"], row["dname"], row["location"])
	}

	fmt.Println("batchInsertSql:", batchInsertSql)
	fmt.Println("values: ", values)
	return batchInsertSql, values
}

func batchPrepareInsertCheckErr(err error){
	if err != nil {
		log.Fatal("系统异常: ", err.Error())
	}
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__4_.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabasePrepareBatchInsertGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database__4_.exe
batchInsertSql: insert into `sys_go_dept` values (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?)
values:  [0 100000011 CPO首席产品官 北京市朝阳区三里屯大街20003号 0 100000044 COO首席营销官 北京市海淀区马连洼30003路 0 100000055 CFO首席财务官 北京市昌平区龙泽苑街道200000 0 100000044 CTO首席技术官 北京市海淀区马连洼30003路 <nil> 100000055 CFO首席财务官 北京市房山区龙泽苑街道200000]
2023/10/19 12:24:41 数据库连接成功!

插入了 5 条数据lastId: 44 insert success!
Process finished with the exit code 0


说明: batchInsertSql: insert into `sys_go_dept` values (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?)

从拼接的insert into `sys_go_dept`语句可以看得出,不用指定具体的插入字段,主键自增长, 此时,主键赋值o或者时nil,从而可以添加全部数据,而不用特意指定那几列添加数据


 九: go语言操作数据看事务处理 


package main

/*
go语言操作数据库时事务处理(ACID)
*/
import (
	"database/sql"
	"fmt"
	"log"

	// 注册驱动器 _下划线表示执行驱动中的init函数,不使用其他函数
	_ "github.com/go-sql-driver/mysql"
)
func main() {
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/tope-pay-user")
	batchPrepareTxInsertCheckErr(err)

	// 延迟执行Closer()函数
	defer db.Close()

	// 验证连接的可用性
	err = db.Ping()
	batchPrepareTxInsertCheckErr(err)
	batchInsertSql, params := initParamDataTx()
	log.Println("数据库连接成功! ")
	tx,err :=db.Begin()
	batchPrepareTxInsertCheckErr(err)
	stmt, err := db.Prepare(batchInsertSql) // 预处理SQL
	checkErrWithTx(err,tx) // 执行回滚
	defer stmt.Close()
	batchPrepareTxInsertCheckErr(err)
	res,err := stmt.Exec(params...)
	checkErrWithTx(err,tx) // 执行回滚
	tx.Commit() // 提交
	println("事务处理完毕")
	id, _ := res.LastInsertId()
	rowCount,err:=res.RowsAffected()
	batchPrepareTxInsertCheckErr(err)
	fmt.Printf("插入了 %d 条数据",rowCount)
	fmt.Printf("lastId: %d insert success!", id)

}

// 插入多条数据
func initParamDataTx() (string, []interface{}) {
	data := []map[string] interface{}{
		{"deptid":0,"deptno": 100000011, "dname": "CPO首席产品官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptid":0,"deptno": 100000044, "dname": "COO首席营销官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":0,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市昌平区龙泽苑街道200000"},
		{"deptid":"0","deptno": 100000044, "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":nil,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市房山区龙泽苑街道200000"},
		{"deptid":0,"deptno": 100000011, "dname": "CPO首席产品官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptid":0,"deptno": 100000044, "dname": "COO首席营销官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":0,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市昌平区龙泽苑街道200000"},
		{"deptid":"0","deptno": 100000066, "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":nil,"deptno": 100000077, "dname": "CFO首席财务官", "location": "北京市房山区龙泽苑街道200000"},
		{"deptid":0,"deptno": 100000011, "dname": "CPO首席产品官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptid":0,"deptno": 100000088, "dname": "COO首席营销官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":0,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市昌平区龙泽苑街道200000"},
		{"deptid":"0","deptno": 100000099, "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":nil,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市房山区龙泽苑街道200000"},
		{"deptid":0,"deptno": 100000011, "dname": "CPO首席产品官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptid":0,"deptno": 100000044, "dname": "COO首席营销官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":0,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市昌平区龙泽苑街道200000"},
		{"deptid":"0","deptno": 100000044, "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":nil,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市房山区龙泽苑街道200000"},
		{"deptid":0,"deptno": 100000011, "dname": "CPO首席产品官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptid":0,"deptno": 100000044, "dname": "COO首席营销官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":0,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市昌平区龙泽苑街道200000"},
		{"deptid":"0","deptno": 100000066, "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":nil,"deptno": 100000077, "dname": "CFO首席财务官", "location": "北京市房山区龙泽苑街道200000"},
		{"deptid":0,"deptno": 100000011, "dname": "CPO首席产品官", "location": "北京市朝阳区三里屯大街20003号"},
		{"deptid":0,"deptno": 100000088, "dname": "COO首席营销官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":0,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市昌平区龙泽苑街道200000"},
		{"deptid":"0","deptno": 100000099, "dname": "CTO首席技术官", "location": "北京市海淀区马连洼30003路"},
		{"deptid":nil,"deptno": 100000055, "dname": "CFO首席财务官", "location": "北京市房山区龙泽苑街道200000"},
	}
	batchInsertSql := "insert into `sys_go_dept` values "
	var values []interface{}
	for index, row := range data {
		if index == len(data)-1 {
			batchInsertSql += "(?,?, ?, ?)"
		} else {
			batchInsertSql += "(?,?, ?, ?), "
		}
		values = append(values,row["deptid"], row["deptno"], row["dname"], row["location"])
	}

	fmt.Println("batchInsertSql:", batchInsertSql)
	fmt.Println("values: ", values)
	return batchInsertSql, values
}

func batchPrepareTxInsertCheckErr(err error){
	if err != nil {
		log.Fatal("系统异常: ", err.Error())
	}
}

// 事务回滚
func checkErrWithTx(err error,tx *sql.Tx) {
	if err != nil {
		tx.Rollback()
		log.Fatal("系统异常,事务将回滚:",err)
	}
}

运行效果:


GOROOT=D:\program_file_worker\go1.20 #gosetup
GOPATH=D:\program_file_worker\go1.20\bin;C:\Users\Administrator\go #gosetup
D:\program_file_worker\go1.20\bin\go.exe build -o C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database.exe D:\program_file\go_workspace\org.jd.data\database\OOPMysqlToDatabaseTxInsertGrammar.go #gosetup
C:\Users\Administrator\AppData\Local\Temp\GoLand\___go_build_org_jd_data_org_jd_data_database.exe
batchInsertSql: insert into `sys_go_dept` values (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?,?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?), (?,?, ?, ?)
values:  [0 100000011 CPO首席产品官 北京市朝阳区三里屯大街20003号 0 100000044 COO首席营销官 北京市海淀区马连洼30003路 0 100000055 CFO首席财务官 北京市昌平区龙泽苑街道200000 0 100000044 CTO首席技术官 北京市海淀区马连洼30003路 <北京市朝阳区三里屯大街20003号 0 100000044 COO首席营销官 北京市海淀区马连洼30003路 0 100000055 CFO首席财务官 北京市昌平区龙泽苑街道200000 0 100000066 CTO首席技术官 北京市海淀区马连洼30003路 <nil> 100000077 CFO首席财务官 北京市房OO首席营销官 北京市海淀区马连洼30003路 0 100000055 CFO首席财务官 北京市昌平区龙泽苑街道200000 0 100000099 CTO首席技术官 北京市海淀区马连洼30003路 <nil> 100000055 CFO首席财务官 北京市房山区龙泽苑街道200000 0 100000011 CPO首席产00055 CFO首席财务官 北京市昌平区龙泽苑街道200000 0 100000044 CTO首席技术官 北京市海淀区马连洼30003路 <nil> 100000055 CFO首席财务官 北京市房山区龙泽苑街道200000 0 100000011 CPO首席产品官 北京市朝阳区三里屯大街20003号 0 100000040 0 100000066 CTO首席技术官 北京市海淀区马连洼30003路 <nil> 100000077 CFO首席财务官 北京市房山区龙泽苑街道200000 0 100000011 CPO首席产品官 北京市朝阳区三里屯大街20003号 0 100000088 COO首席营销官 北京市海淀区马连洼30003路 0 100洼30003路 <nil> 100000055 CFO首席财务官 北京市房山区龙泽苑街道200000]
2023/10/19 13:17:03 数据库连接成功!
事务处理完毕
插入了 30 条数据lastId: 89 insert success!


Process finished with the exit code 0
 

十: 异常:converting argument $1 type: unsupported type []interface {}, a slice of interface


log.Println("数据库连接成功! ")
    tx,err :=db.Begin()
    batchPrepareTxInsertCheckErr(err)
    stmt, err := db.Prepare(batchInsertSql) // 预处理SQL
    checkErrWithTx(err,tx) // 执行回滚
    defer stmt.Close()
    batchPrepareTxInsertCheckErr(err)
    res,err := stmt.Exec(params)
    checkErrWithTx(err,tx) // 执行回滚
    tx.Commit() // 提交
    println("事务处理完毕")
    id, _ := res.LastInsertId()

如上述代码,stmt.Exec(params) 出入参数即报错: sql: converting argument $1 type: unsupported type []interface {}, a slice of interface;

字面意思是sqlx在解析两个占位符并试图填入参数时,第一个参数类型是空指针的切片,而预期是args这个可变参数中的第一个。
因而了解了一下golang中的可变参数,即…运算符
当…Type做为参数时,本质上函数会把参数转化成一个Type类型的切片,因而在上述代码中,Service层调以可变参数形式传入一个参数,在Exec中的args就已经是[]interface{}类型了,若是直接把args做为func (s *Stmt) Exec args …interface{}) (Result, error)的参数,对于Exec来讲,收到的args就只有一个长度为1的切片,其元素类型为[]interface{},因而就有了上述的报错,解决办法很简单,就是在一个slice后加上…,这样就能把它拆包成一个可变参数的形式传入函数。

可以查看下Exce源代码:

/ Exec executes a prepared statement with the given arguments and
// returns a Result summarizing the effect of the statement.
//
// Exec uses context.Background internally; to specify the context, use
// ExecContext.
func (s *Stmt) Exec(args ...any) (Result, error) {
   return s.ExecContext(context.Background(), args...)
}

入参为可变参数: 函数会把参数转化成一个Type类型的切片,正确的调用方式应该是这样:

res,err := stmt.Exec(params...) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1110420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在前端html页面中向服务器发送post登录请求

目录 前言 搭建服务器 搭建前端登录页面 获取表单值 使用axios发送post登录请求 前言 一般在html页面中向服务器发送post请求的模块为登录请求&#xff0c;本文将介绍如何向服务器发送post请求 搭建服务器 如何搭建服务器请看JWT认证这篇文章&#xff0c;有详细的解说。…

垃圾邮件(短信)分类算法实现 机器学习 深度学习 计算机竞赛

文章目录 0 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 垃圾邮件(短信)分类算…

SVN一直报错Error running context: 由于目标计算机积极拒绝,无法连接。解决办法【杭州多测师_王sir】...

一、发现SVN一直报错Error running context: 由于目标计算机积极拒绝&#xff0c;无法连接。 二、没有启动 VisualSVN Server。cmd--> services.msc打开本地服务。查看VisualSVN的三个服务的启动类型&#xff0c;建议选择“手动”&#xff0c;不能选择“禁用”&#xff0c;选…

跨境电商自养号测评:如何配置安全可靠的网络环境?

随着全球化的加速和互联网的普及&#xff0c;跨境电商已经逐渐成为全球电子商务的主流形式。越来越多的企业开始涉足跨境电商领域&#xff0c;希望通过跨越国界的贸易活动来扩大市场份额、提高品牌影响力&#xff0c;以及增加企业收益。 然而跨境电商是一个充满机遇和挑战的领…

C++入门(c++历史篇)

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 重点 1. 什么是C2. C的发展…

《计算机病毒技术及其防御》 第一章 课后练习详解

简述计算机病毒定义及相关起源。 计算机病毒&#xff08;狭义的&#xff09;定义为&#xff1a;计算机病毒是指编制或者在计算机程序中插入的破坏计算机功能或者毁坏数据&#xff0c;影响计算机使用&#xff0c;并能自我复制的一组计算机指令或者程序代码。 广义的计算机病毒&…

如何用云服务器搭建网站、多个站点(不使用域名仅用公网IP)---保姆级教学

前言 本篇文章帮助初学者小白搭建网站及站点 本人也是刚刚接触这个领域&#xff0c;希望能帮助到大家。 文章目录 前言1.购买服务器2.部署工作3.安装宝塔面板4.利用公网IP搭建站点5.如何搭建多个站点和网站&#xff1f; 1.购买服务器 链接: 阿里云服务器官网 2.部署工作 …

21天打卡掌握java基础操作

Java安装环境变量配置-day1 参考&#xff1a; https://www.runoob.com/w3cnote/windows10-java-setup.html 生成class文件 java21天打卡-day2 输入和输出 题目&#xff1a;设计一个程序&#xff0c;输入上次考试成绩&#xff08;int&#xff09;和本次考试成绩&#xff0…

博睿数据 Bonree ONE 秋季产品发布会,即将震撼启幕!

云原生、Devops等技术的发展&#xff0c;为企业的生产与发展带来极大好处的同时分布式架构的增加、繁琐的数据、复杂的依赖关系和弹性架构等&#xff0c;都进一步增加了运维的压力和复杂度。如何降低运维的复杂度&#xff0c;释放运维工作潜能&#xff0c;提升工作效率&#xf…

实时配送跟踪功能的实现:外卖跑腿小程序的技术挑战

在当今数字化时代&#xff0c;外卖和跑腿服务已经成为了生活中不可或缺的一部分。为了提供更好的用户体验&#xff0c;外卖跑腿小程序越来越注重实时配送跟踪功能的实现。这项技术挑战旨在确保顾客可以方便地跟踪他们的订单&#xff0c;以及配送员可以高效地完成送货任务。本文…

基于Flume+Kafka+Hbase+Flink+FineBI的实时综合案例(五)FineBI可视化

文章目录 22&#xff1a;FineBI配置数据集23&#xff1a;FineBI构建报表24&#xff1a;FineBI实时配置测试附录二&#xff1a;离线消费者完整代码 22&#xff1a;FineBI配置数据集 目标&#xff1a;实现FineBI访问MySQL结果数据集的配置 实施 安装FineBI 参考《FineBI Windows…

使用Nginx可视化管理工具+Cpolar在本地搭建服务器并实现远程访问【内网穿透】

文章目录 前言1. docker 一键安装2. 本地访问3. Linux 安装cpolar4. 配置公网访问地址5. 公网远程访问6. 固定公网地址 前言 Nginx Proxy Manager 是一个开源的反向代理工具&#xff0c;不需要了解太多 Nginx 或 Letsencrypt 的相关知识&#xff0c;即可快速将你的服务暴露到外…

【MyBatis】mvc模式以及Mapper文件中的namespace以及ORM思想

目录 什么是MVC三层架构&#xff0c;初步了解&#xff1f; namespace的作用是什么&#xff1f; Mapper文件中的namespace&#xff1f; ORM思想&#xff08;对象关系映射思想&#xff09; 其中提供了一套映射规则和API 什么是MVC三层架构&#xff0c;初步了解&#xff1f; 三…

谷歌浏览器多版本切换测试兼容性

谷歌浏览器多版本切换测试兼容性 在开发过程中&#xff0c;我们常常会出现浏览器兼容问题&#xff0c;客户的浏览器版本参差不齐&#xff0c;只有对应版本的浏览器才会出现对应的问题&#xff0c;所以我们需要在本地通过切换不同的浏览器来测试对应的问题。本篇内容就是介绍不用…

投资理财:增额终身寿的优点和缺点

大家好&#xff0c;我是财富智星&#xff0c;今天跟大家继续探讨一下最近理财爆火的增额终身寿&#xff0c;你是真的了解增额终身寿的本质吗&#xff1f; 一、增额寿3.0%的利率真的吸引人吗&#xff1f; 身边有很多富有的成功人士以及财经博主都开始购买增额终身寿保险&#xf…

中国人民大学与加拿大女王大学金融硕士庞雪雨:行学之道,在自律、在勤勉、在止于至善

庞雪雨 中国人民大学-加拿大女王大学金融硕士2022-2023级行业高管班 光大保德信资产管理有限公司董事总经理 当我进入到人大校园的那一刻&#xff0c;映入眼帘的是明德楼&#xff0c;由此我想到了《大学》&#xff0c;大学开篇中讲到&#xff0c;大学之道&#xff0c;在明明德…

Maven 基础教程系列

Maven是一个项目开发管理和理解工具。基于项目对象模型的概念&#xff1a;构建、依赖关系管理、文档创建、站点发布和分发发布都由pom.xml声明性文件控制。Maven可以通过插件进行扩展&#xff0c;以使用许多其他开发工具来报告或构建过程。 一、Maven 使用教程-CSDN博客 二、…

电源芯片测试规范是什么?如何测试电源芯片输入电压范围?

电源芯片测试贯穿着研发、设计、生产过程的始终&#xff0c;目的就是为了通过反复检测来确保电源芯片的性能、质量和可靠性&#xff0c;保证正常工作运行。电源芯片测试涉及到许多测试项目&#xff0c;并且有着具体的测试规范标准和方法。本文纳米软件将介绍电源芯片输入电压范…

Flutter视图原理之StatefulWidget,InheritedWidget

目录 StatefulElement1. 构造函数2. build3. _firstBuild3. didChangeDependencies4. setState InheritedElement1. Element类2. _updateInheritance3. InheritedWidget数据向下传递3.1 dependOnInheritedWidgetOfExactType 4. InheritedWidget的状态绑定4.1. ProxyElement 在f…

为中小企业的网络推广策略解析:扩大品牌知名度和曝光度

目前网络推广已经成为企业获取潜在客户和提升品牌知名度的重要手段。对于中小企业而言&#xff0c;网络推广是一个具有巨大潜力和可行性的营销策略。在本文中&#xff0c;我们将探讨中小企业为什么有必要进行网络推广&#xff0c;并分享一些实用的网络推广策略。 一、扩大品牌知…