golang的巢狀事務管理
golang 的事務管理是一件很麻煩的事,,能不能像 Java 那樣,通過 Spring 管理事務,最近琢磨了一下,寫了一個 demo,用來管理 golang 的事務,使其支援 golang 事務的巢狀呼叫。
其思想很簡單,對於所有的寫資料庫操作,用一個標記來標記事務的開啟和關閉 下面是一個演示示例:
我只是寫了一個簡單 demo,這裡貼出實現程式碼:
package session
import (
"database/sql"
)
const beginStatus = 1
// SessionFactory 會話工廠
type SessionFactory struct {
*sql.DB
}
// Session 會話
type Session struct {
db *sql.DB // 原生db
tx *sql.Tx // 原生事務
commitSign int8 // 提交標記,控制是否提交事務
rollbackSign bool // 回滾標記,控制是否回滾事務
}
// NewSessionFactory 建立一個會話工廠
func NewSessionFactory(driverName, dataSourseName string) (*SessionFactory, error) {
db, err := sql.Open(driverName, dataSourseName)
if err != nil {
panic(err)
}
factory := new(SessionFactory)
factory.DB = db
return factory, nil
}
// GetSession 獲取一個Session
func (sf *SessionFactory) GetSession() *Session {
session := new(Session)
session.db = sf.DB
return session
}
// Begin 開啟事務
func (s *Session) Begin() error {
s.rollbackSign = true
if s.tx == nil {
tx, err := s.db.Begin()
if err != nil {
return err
}
s.tx = tx
s.commitSign = beginStatus
return nil
}
s.commitSign++
return nil
}
// Rollback 回滾事務
func (s *Session) Rollback() error {
if s.tx != nil && s.rollbackSign == true {
err := s.tx.Rollback()
if err != nil {
return err
}
s.tx = nil
return nil
}
return nil
}
// Commit 提交事務
func (s *Session) Commit() error {
s.rollbackSign = false
if s.tx != nil {
if s.commitSign == beginStatus {
err := s.tx.Commit()
if err != nil {
return err
}
s.tx = nil
return nil
} else {
s.commitSign--
}
return nil
}
return nil
}
// Exec 執行sql語句,如果已經開啟事務,就以事務方式執行,如果沒有開啟事務,就以非事務方式執行
func (s *Session) Exec(query string, args ...interface{}) (sql.Result, error) {
if s.tx != nil {
return s.tx.Exec(query, args...)
}
return s.db.Exec(query, args...)
}
// QueryRow 如果已經開啟事務,就以事務方式執行,如果沒有開啟事務,就以非事務方式執行
func (s *Session) QueryRow(query string, args ...interface{}) *sql.Row {
if s.tx != nil {
return s.tx.QueryRow(query, args...)
}
return s.db.QueryRow(query, args...)
}
// Query 查詢資料,如果已經開啟事務,就以事務方式執行,如果沒有開啟事務,就以非事務方式執行
func (s *Session) Query(query string, args ...interface{}) (*sql.Rows, error) {
if s.tx != nil {
return s.tx.Query(query, args...)
}
return s.db.Query(query, args...)
}
// Prepare 預執行,如果已經開啟事務,就以事務方式執行,如果沒有開啟事務,就以非事務方式執行
func (s *Session) Prepare(query string) (*sql.Stmt, error) {
if s.tx != nil {
return s.tx.Prepare(query)
}
return s.db.Prepare(query)
}
測試用例:
package session
import (
_ "github.com/go-sql-driver/mysql"
"testing"
"fmt"
)
var sf *SessionFactory
func init() {
var err error
sf, err = NewSessionFactory("mysql", "root:Liu123456@tcp(localhost:3306)/test?charset=utf8")
if err != nil {
fmt.Println(err)
panic(err)
}
}
type User struct {
mobile string
name string
age int
sex int
}
type UserService struct {
session *Session
}
func NewUserService() *UserService {
return &UserService{sf.GetSession()}
}
func (s *UserService) Insert(user User) error {
_, err := s.session.Exec("insert into user(mobile,name,age,sex) values(?,?,?,?)",
user.mobile, user.name, user.age, user.sex)
return err
}
func (s *UserService) AddInTx(user1, user2 User) error {
err := s.session.Begin()
if err != nil {
return err
}
defer s.session.Rollback()
err = s.Insert(user1)
if err != nil {
fmt.Println(err)
return err
}
// return errors.New("err") 回滾測試
err = s.Insert(user2)
if err != nil {
fmt.Println(err)
return err
}
s.session.Commit()
return nil
}
// DoNestingTx 巢狀事務
func (s *UserService) DoNestingTx() {
err := s.session.Begin()
if err != nil {
fmt.Println(err)
}
defer s.session.Rollback()
err = s.Insert(User{mobile: "1", name: "1", age: 1, sex: 1})
if err != nil {
fmt.Println(err)
return
}
err = s.AddInTx(User{mobile: "1", name: "1", age: 1, sex: 1}, User{mobile: "1", name: "1", age: 1, sex: 1})
if err != nil {
fmt.Println(err)
return
}
err = s.session.Commit()
if err != nil {
fmt.Println(err)
return
}
}
// TestDoNestingTx 測試巢狀事務
func TestDoNestingTx(t *testing.T) {
userService := NewUserService()
userService.DoNestingTx()
}
GitHub:https://github.com/alberliu/session
更多原創文章乾貨分享,請關注公眾號
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 關於 MySQL 的巢狀事務MySql巢狀
- sql server中巢狀事務*SQLServer巢狀
- Oracle 巢狀事務 VS 自治事務Oracle巢狀
- SQL Server中存在真正的“事務巢狀”SQLServer巢狀
- Laravel 之巢狀事務 transactions 實現Laravel巢狀
- java spring巢狀事務詳情和事務傳播型別JavaSpring巢狀型別
- Locust 任務巢狀巢狀
- Spring中事務巢狀這麼用一定得注意了!!Spring巢狀
- java定時任務巢狀Java巢狀
- Spring的事務管理(二)宣告式事務管理Spring
- Spring的事務管理Spring
- Vue中的巢狀路由Vue巢狀路由
- html的巢狀規則HTML巢狀
- 事務狀態持久化持久化
- Spring的事務管理入門:程式設計式事務管理(TransactionTemplate)Spring程式設計
- Spring 中的事務管理Spring
- 列表巢狀操作巢狀
- vue路由巢狀Vue路由巢狀
- Spring 事務管理Spring
- 008. vue元件的巢狀Vue元件巢狀
- JavaScript中if巢狀assert的方法JavaScript巢狀
- vue的元件巢狀關係Vue元件巢狀
- DTM:Golang中微服務架構的分散式事務框架Golang微服務架構分散式框架
- (四)Spring中的事務管理Spring
- 巢狀類遞迴巢狀遞迴
- Blazor巢狀傳遞Blazor巢狀
- 展開巢狀列表巢狀
- vue(19)巢狀路由Vue巢狀路由
- Oracle 巢狀表(轉)Oracle巢狀
- 巢狀子查詢巢狀
- SCSS 巢狀屬性CSS巢狀
- SCSS 巢狀規則CSS巢狀
- golang如何優雅的編寫事務程式碼Golang
- MySQL Join原理分析(緩衝塊巢狀與索引巢狀迴圈)MySql巢狀索引
- Revit獲取元素的巢狀族巢狀
- Elasticsearch聚合的巢狀桶如何排序Elasticsearch巢狀排序
- javafx和swing巢狀使用的方法Java巢狀
- JavaScript巢狀物件的全新方式JavaScript巢狀物件