init
This commit is contained in:
+209
@@ -0,0 +1,209 @@
|
||||
package umsql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"AngkorWalletScanning/model"
|
||||
"AngkorWalletScanning/umlog"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
// type DB_handler struct {
|
||||
// conn *sql.DB
|
||||
// }
|
||||
|
||||
func DbConnect(host string, port string, user string, password string, dbname string) *sql.DB {
|
||||
conn, connect_err := sql.Open("mysql", user+":"+password+"@tcp("+host+":"+port+")/"+dbname)
|
||||
if connect_err != nil {
|
||||
umlog.Error(connect_err.Error())
|
||||
panic(connect_err.Error())
|
||||
}
|
||||
conn.SetConnMaxLifetime(time.Minute * 3)
|
||||
conn.SetMaxOpenConns(1000)
|
||||
conn.SetMaxIdleConns(1000)
|
||||
return conn
|
||||
}
|
||||
|
||||
func DbDisconnect(connA *sql.DB) {
|
||||
umlog.Debug("DataBase DISCONNECTION")
|
||||
err := connA.Close()
|
||||
if err != nil {
|
||||
umlog.Warn("DataBase DISCONNECTION Error A: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func DbBegin(conn *sql.DB) (*sql.Tx, error) {
|
||||
if conn != nil {
|
||||
return conn.Begin()
|
||||
} else {
|
||||
return nil, errors.New("db connecter is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func DbRollback(tx *sql.Tx) error {
|
||||
return tx.Rollback()
|
||||
}
|
||||
|
||||
func DbCommit(tx *sql.Tx) error {
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func SqlSelect(conn *sql.DB, query string, args ...any) (*sql.Rows, []string, error) {
|
||||
var rows *sql.Rows
|
||||
var err error
|
||||
|
||||
if conn != nil {
|
||||
if len(args) == 0 {
|
||||
rows, err = conn.Query(query)
|
||||
} else {
|
||||
rows, err = conn.Query(query, args...)
|
||||
}
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return nil, nil, err
|
||||
}
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return nil, nil, err
|
||||
}
|
||||
return rows, cols, nil
|
||||
}
|
||||
umlog.Error("db connecter is nil")
|
||||
return nil, nil, errors.New("db connecter is nil")
|
||||
}
|
||||
|
||||
func SqlTxExecute(tx *sql.Tx, query string, args ...any) (int64, error) {
|
||||
var result sql.Result
|
||||
var err error
|
||||
|
||||
if tx != nil {
|
||||
if len(args) == 0 {
|
||||
result, err = tx.Exec(query)
|
||||
} else {
|
||||
result, err = tx.Exec(query, args...)
|
||||
}
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return -1, err
|
||||
}
|
||||
n, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return -1, err
|
||||
}
|
||||
return n, nil
|
||||
} else {
|
||||
umlog.Error("tx is nil")
|
||||
return -1, errors.New("tx is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func SqlExecute(conn *sql.DB, query string, args ...any) (int64, error) {
|
||||
var result sql.Result
|
||||
var err error
|
||||
|
||||
if conn != nil {
|
||||
if len(args) == 0 {
|
||||
result, err = conn.Exec(query)
|
||||
} else {
|
||||
result, err = conn.Exec(query, args...)
|
||||
}
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return -1, err
|
||||
}
|
||||
n, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return -1, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
umlog.Error("db connecter is nil")
|
||||
return -1, errors.New("db connecter is nil")
|
||||
}
|
||||
|
||||
func SqlStatement(conn *sql.DB, sql string, param [][]string) error {
|
||||
stmt, err := conn.Prepare(sql)
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
for i, sub_val := range param {
|
||||
fmt.Println(sub_val)
|
||||
err = sqlStatementExec(stmt, param[i], len(param[i]))
|
||||
if err != nil {
|
||||
umlog.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sqlStatementExec(stmt *sql.Stmt, param []string, param_count int) error {
|
||||
args := make([]interface{}, param_count)
|
||||
for i, v := range param {
|
||||
args[i] = v
|
||||
}
|
||||
_, err := stmt.Exec(args...)
|
||||
return err
|
||||
}
|
||||
|
||||
func SqlTransaction(conn *sql.DB, maxRetries int, txFunc func(*sql.Tx) error) model.DefaultErrorModel {
|
||||
var err error
|
||||
var value string
|
||||
for i := 0; i <= maxRetries; i++ {
|
||||
tx, beginErr := conn.Begin()
|
||||
if beginErr != nil {
|
||||
return model.DefaultErrorModel{Code: 4001201, Message: fmt.Sprintf("failed to begin transaction: %v", beginErr)}
|
||||
}
|
||||
|
||||
err = txFunc(tx)
|
||||
|
||||
if err != nil {
|
||||
// 트랜잭션 롤백
|
||||
_ = tx.Rollback()
|
||||
|
||||
// 1205 오류인지 확인
|
||||
if isLockWaitTimeout(err) {
|
||||
umlog.Info(value + ": Transaction lock timeout (1205), retrying... (" + strconv.Itoa(i+1) + "/" + strconv.Itoa(maxRetries) + ")")
|
||||
time.Sleep(time.Duration(100*(i+1)) * time.Millisecond) // simple backoff
|
||||
continue
|
||||
}
|
||||
return model.DefaultErrorModel{Code: 4001201, Message: fmt.Sprintf("transaction failed: %v", err)}
|
||||
}
|
||||
|
||||
// 커밋 시도
|
||||
commitErr := tx.Commit()
|
||||
if commitErr != nil {
|
||||
// 커밋 중 에러가 1205일 수도 있음
|
||||
if isLockWaitTimeout(commitErr) {
|
||||
umlog.Info(value + ": Commit failed due to lock timeout, retrying... (" + strconv.Itoa(i+1) + "/" + strconv.Itoa(maxRetries) + ")")
|
||||
time.Sleep(time.Duration(100*(i+1)) * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
umlog.Error(value + ": commit error: " + commitErr.Error())
|
||||
return model.DefaultErrorModel{Code: 4001201, Message: fmt.Sprintf("commit error: %v", commitErr)}
|
||||
}
|
||||
// 성공
|
||||
return model.DefaultErrorModel{Code: 200, Message: ""}
|
||||
}
|
||||
|
||||
umlog.Error(value + ": Transaction failed after " + strconv.Itoa(maxRetries) + " retries: " + err.Error())
|
||||
return model.DefaultErrorModel{Code: 4001201, Message: fmt.Sprintf("%s: Transaction failed after %d retries: %w", value, maxRetries, err)}
|
||||
}
|
||||
|
||||
func isLockWaitTimeout(err error) bool {
|
||||
// mysql 드라이버의 오류 메시지에서 1205 감지
|
||||
return err != nil && (strings.Contains(err.Error(), "Error 1205") || strings.Contains(err.Error(), "Lock wait timeout"))
|
||||
}
|
||||
Reference in New Issue
Block a user