使用Golang实现MySQL中表A和表B的插入操作及一体处理
使用Golang实现MySQL中表A和表B的插入操作及一体处理 如何用Go语言一次性处理向MySQL数据库的tableA和tableB插入数据?
package main
import (
"context"
"database/sql"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
const (
username = "root"
password = "root"
hostname = "localhost:3306"
dbname = "ecommerce"
)
func dsn(dbName string) string {
return fmt.Sprintf("%s:%s@tcp(%s)/%s", username, password, hostname, dbName)
}
func dbConnection() (*sql.DB, error) {
db, err := sql.Open("mysql", dsn(""))
if err != nil {
log.Printf("Error %s when opening DB\n", err)
return nil, err
}
//defer db.Close()
ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
res, err := db.ExecContext(ctx, "CREATE DATABASE IF NOT EXISTS "+dbname)
if err != nil {
log.Printf("Error %s when creating DB\n", err)
return nil, err
}
no, err := res.RowsAffected()
if err != nil {
log.Printf("Error %s when fetching rows", err)
return nil, err
}
log.Printf("rows affected %d\n", no)
db.Close()
db, err = sql.Open("mysql", dsn(dbname))
if err != nil {
log.Printf("Error %s when opening DB", err)
return nil, err
}
//defer db.Close()
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(20)
db.SetConnMaxLifetime(time.Minute * 5)
ctx, cancelfunc = context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
err = db.PingContext(ctx)
if err != nil {
log.Printf("Errors %s pinging DB", err)
return nil, err
}
log.Printf("Connected to DB %s successfully\n", dbname)
return db, nil
}
func createProductTable(db *sql.DB) error {
query := `CREATE TABLE IF NOT EXISTS product(product_id int primary key auto_increment, product_name text, product_price int, created_at datetime default CURRENT_TIMESTAMP, updated_at datetime default CURRENT_TIMESTAMP)`
ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
res, err := db.ExecContext(ctx, query)
if err != nil {
log.Printf("Error %s when creating product table", err)
return err
}
rows, err := res.RowsAffected()
if err != nil {
log.Printf("Error %s when getting rows affected", err)
return err
}
log.Printf("Rows affected when creating table: %d", rows)
return nil
}
func main() {
db, err := dbConnection()
if err != nil {
log.Printf("Error %s when getting db connection", err)
return
}
defer db.Close()
log.Printf("Successfully connected to database")
err = createProductTable(db)
if err != nil {
log.Printf("Create product table failed with error %s", err)
return
}
}
更多关于使用Golang实现MySQL中表A和表B的插入操作及一体处理的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
你的具体问题是什么?运行代码时是否有任何错误,还是数据没有按你预期的方式显示,或者你到底遇到了什么问题?
更多关于使用Golang实现MySQL中表A和表B的插入操作及一体处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中实现MySQL表A和表B的原子性插入操作,需要使用事务(Transaction)来确保数据一致性。以下是完整的实现示例:
package main
import (
"context"
"database/sql"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
const (
username = "root"
password = "root"
hostname = "localhost:3306"
dbname = "ecommerce"
)
// 创建表A和表B
func createTables(db *sql.DB) error {
// 创建表A
queryA := `CREATE TABLE IF NOT EXISTS tableA(
id int primary key auto_increment,
name varchar(100) not null,
value int,
created_at datetime default CURRENT_TIMESTAMP
)`
// 创建表B
queryB := `CREATE TABLE IF NOT EXISTS tableB(
id int primary key auto_increment,
a_id int not null,
description text,
amount decimal(10,2),
created_at datetime default CURRENT_TIMESTAMP,
FOREIGN KEY (a_id) REFERENCES tableA(id)
)`
ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelfunc()
// 创建表A
_, err := db.ExecContext(ctx, queryA)
if err != nil {
log.Printf("Error creating tableA: %v", err)
return err
}
// 创建表B
_, err = db.ExecContext(ctx, queryB)
if err != nil {
log.Printf("Error creating tableB: %v", err)
return err
}
log.Println("Tables created successfully")
return nil
}
// 原子性插入数据到表A和表B
func insertDataAtomically(db *sql.DB, aName string, aValue int, bDescription string, bAmount float64) error {
// 开始事务
tx, err := db.Begin()
if err != nil {
return fmt.Errorf("begin transaction failed: %v", err)
}
// 确保事务在函数结束时要么提交要么回滚
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p)
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
// 插入表A数据
var aID int64
result, err := tx.Exec(
"INSERT INTO tableA(name, value) VALUES(?, ?)",
aName, aValue,
)
if err != nil {
return fmt.Errorf("insert into tableA failed: %v", err)
}
// 获取表A的自增ID
aID, err = result.LastInsertId()
if err != nil {
return fmt.Errorf("get last insert id failed: %v", err)
}
// 插入表B数据,使用表A的ID作为外键
_, err = tx.Exec(
"INSERT INTO tableB(a_id, description, amount) VALUES(?, ?, ?)",
aID, bDescription, bAmount,
)
if err != nil {
return fmt.Errorf("insert into tableB failed: %v", err)
}
log.Printf("Successfully inserted data with transaction. TableA ID: %d", aID)
return nil
}
// 使用上下文进行事务处理
func insertDataWithContext(db *sql.DB, aName string, aValue int, bDescription string, bAmount float64) error {
ctx := context.Background()
// 开始带上下文的事务
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("begin transaction failed: %v", err)
}
// 插入表A数据
result, err := tx.ExecContext(ctx,
"INSERT INTO tableA(name, value) VALUES(?, ?)",
aName, aValue,
)
if err != nil {
tx.Rollback()
return fmt.Errorf("insert into tableA failed: %v", err)
}
// 获取表A的自增ID
aID, err := result.LastInsertId()
if err != nil {
tx.Rollback()
return fmt.Errorf("get last insert id failed: %v", err)
}
// 插入表B数据
_, err = tx.ExecContext(ctx,
"INSERT INTO tableB(a_id, description, amount) VALUES(?, ?, ?)",
aID, bDescription, bAmount,
)
if err != nil {
tx.Rollback()
return fmt.Errorf("insert into tableB failed: %v", err)
}
// 提交事务
if err := tx.Commit(); err != nil {
return fmt.Errorf("commit transaction failed: %v", err)
}
log.Printf("Successfully inserted data with context. TableA ID: %d", aID)
return nil
}
// 批量插入示例
func batchInsertData(db *sql.DB, data []struct {
aName string
aValue int
bDescription string
bAmount float64
}) error {
tx, err := db.Begin()
if err != nil {
return fmt.Errorf("begin transaction failed: %v", err)
}
defer func() {
if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
for _, item := range data {
// 插入表A
result, err := tx.Exec(
"INSERT INTO tableA(name, value) VALUES(?, ?)",
item.aName, item.aValue,
)
if err != nil {
return fmt.Errorf("insert into tableA failed: %v", err)
}
// 获取自增ID
aID, err := result.LastInsertId()
if err != nil {
return fmt.Errorf("get last insert id failed: %v", err)
}
// 插入表B
_, err = tx.Exec(
"INSERT INTO tableB(a_id, description, amount) VALUES(?, ?, ?)",
aID, item.bDescription, item.bAmount,
)
if err != nil {
return fmt.Errorf("insert into tableB failed: %v", err)
}
}
log.Printf("Successfully batch inserted %d records", len(data))
return nil
}
func main() {
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", username, password, hostname, dbname))
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 设置连接池参数
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(time.Minute * 5)
// 测试连接
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
log.Fatal(err)
}
// 创建表
if err := createTables(db); err != nil {
log.Fatal(err)
}
// 示例1: 原子性插入单条数据
err = insertDataAtomically(db, "Product1", 100, "Description for product1", 99.99)
if err != nil {
log.Printf("Atomic insert failed: %v", err)
}
// 示例2: 使用上下文插入数据
err = insertDataWithContext(db, "Product2", 200, "Description for product2", 199.99)
if err != nil {
log.Printf("Context insert failed: %v", err)
}
// 示例3: 批量插入数据
batchData := []struct {
aName string
aValue int
bDescription string
bAmount float64
}{
{"Product3", 300, "Description 3", 299.99},
{"Product4", 400, "Description 4", 399.99},
{"Product5", 500, "Description 5", 499.99},
}
err = batchInsertData(db, batchData)
if err != nil {
log.Printf("Batch insert failed: %v", err)
}
}
这个实现提供了三种方式处理表A和表B的原子性插入:
- 基础事务处理 (
insertDataAtomically):使用标准的Begin()、Commit()和Rollback()方法 - 带上下文的事务处理 (
insertDataWithContext):使用BeginTx()支持上下文取消和超时 - 批量事务处理 (
batchInsertData):在单个事务中处理多条记录插入
所有方法都确保要么两个表都插入成功,要么都失败回滚,保持数据一致性。

