Add log track on prepare & tx
This commit is contained in:
parent
c8b4ea56bc
commit
046c6bc7e5
59
core/stmt.go
59
core/stmt.go
|
@ -9,6 +9,9 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"xorm.io/xorm/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Stmt reprents a stmt objects
|
// Stmt reprents a stmt objects
|
||||||
|
@ -16,6 +19,7 @@ type Stmt struct {
|
||||||
*sql.Stmt
|
*sql.Stmt
|
||||||
db *DB
|
db *DB
|
||||||
names map[string]int
|
names map[string]int
|
||||||
|
query string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||||
|
@ -27,11 +31,27 @@ func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||||
return "?"
|
return "?"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
if db.Logger != nil {
|
||||||
|
db.Logger.BeforeSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: "PREPARE",
|
||||||
|
})
|
||||||
|
}
|
||||||
stmt, err := db.DB.PrepareContext(ctx, query)
|
stmt, err := db.DB.PrepareContext(ctx, query)
|
||||||
|
if db.Logger != nil {
|
||||||
|
db.Logger.AfterSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: "PREPARE",
|
||||||
|
ExecuteTime: time.Now().Sub(start),
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Stmt{stmt, db, names}, nil
|
|
||||||
|
return &Stmt{stmt, db, names, query}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Prepare(query string) (*Stmt, error) {
|
func (db *DB) Prepare(query string) (*Stmt, error) {
|
||||||
|
@ -73,11 +93,46 @@ func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error) {
|
func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (sql.Result, error) {
|
||||||
return s.Stmt.ExecContext(ctx, args)
|
start := time.Now()
|
||||||
|
if s.db.Logger != nil {
|
||||||
|
s.db.Logger.BeforeSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: s.query,
|
||||||
|
Args: args,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res, err := s.Stmt.ExecContext(ctx, args)
|
||||||
|
if s.db.Logger != nil {
|
||||||
|
s.db.Logger.AfterSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: s.query,
|
||||||
|
Args: args,
|
||||||
|
ExecuteTime: time.Now().Sub(start),
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
|
func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
|
||||||
|
start := time.Now()
|
||||||
|
if s.db.Logger != nil {
|
||||||
|
s.db.Logger.BeforeSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: s.query,
|
||||||
|
Args: args,
|
||||||
|
})
|
||||||
|
}
|
||||||
rows, err := s.Stmt.QueryContext(ctx, args...)
|
rows, err := s.Stmt.QueryContext(ctx, args...)
|
||||||
|
if s.db.Logger != nil {
|
||||||
|
s.db.Logger.AfterSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: s.query,
|
||||||
|
Args: args,
|
||||||
|
ExecuteTime: time.Now().Sub(start),
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
38
core/tx.go
38
core/tx.go
|
@ -18,7 +18,22 @@ type Tx struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||||
|
start := time.Now()
|
||||||
|
if db.Logger != nil {
|
||||||
|
db.Logger.BeforeSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: "BEGIN TRANSACTION",
|
||||||
|
})
|
||||||
|
}
|
||||||
tx, err := db.DB.BeginTx(ctx, opts)
|
tx, err := db.DB.BeginTx(ctx, opts)
|
||||||
|
if db.Logger != nil {
|
||||||
|
db.Logger.AfterSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: "BEGIN TRANSACTION",
|
||||||
|
ExecuteTime: time.Now().Sub(start),
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -26,11 +41,7 @@ func (db *DB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Begin() (*Tx, error) {
|
func (db *DB) Begin() (*Tx, error) {
|
||||||
tx, err := db.DB.Begin()
|
return db.BeginTx(context.Background(), nil)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Tx{tx, db}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||||
|
@ -42,11 +53,26 @@ func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||||
return "?"
|
return "?"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
if tx.db.Logger != nil {
|
||||||
|
tx.db.Logger.BeforeSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: "PREPARE",
|
||||||
|
})
|
||||||
|
}
|
||||||
stmt, err := tx.Tx.PrepareContext(ctx, query)
|
stmt, err := tx.Tx.PrepareContext(ctx, query)
|
||||||
|
if tx.db.Logger != nil {
|
||||||
|
tx.db.Logger.AfterSQL(log.LogContext{
|
||||||
|
Ctx: ctx,
|
||||||
|
SQL: "PREPARE",
|
||||||
|
ExecuteTime: time.Now().Sub(start),
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Stmt{stmt, tx.db, names}, nil
|
return &Stmt{stmt, tx.db, names, query}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Tx) Prepare(query string) (*Stmt, error) {
|
func (tx *Tx) Prepare(query string) (*Stmt, error) {
|
||||||
|
|
|
@ -45,7 +45,6 @@ type Dialect interface {
|
||||||
IsReserved(string) bool
|
IsReserved(string) bool
|
||||||
Quoter() schemas.Quoter
|
Quoter() schemas.Quoter
|
||||||
|
|
||||||
RollBackStr() string
|
|
||||||
AutoIncrStr() string
|
AutoIncrStr() string
|
||||||
|
|
||||||
SupportInsertMany() bool
|
SupportInsertMany() bool
|
||||||
|
@ -178,10 +177,6 @@ func (b *Base) DataSourceName() string {
|
||||||
return b.dataSourceName
|
return b.dataSourceName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Base) RollBackStr() string {
|
|
||||||
return "ROLL BACK"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *Base) SupportDropIfExists() bool {
|
func (db *Base) SupportDropIfExists() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
117
session_tx.go
117
session_tx.go
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"xorm.io/xorm/log"
|
||||||
|
)
|
||||||
|
|
||||||
// Begin a transaction
|
// Begin a transaction
|
||||||
func (session *Session) Begin() error {
|
func (session *Session) Begin() error {
|
||||||
if session.isAutoCommit {
|
if session.isAutoCommit {
|
||||||
|
@ -14,6 +20,7 @@ func (session *Session) Begin() error {
|
||||||
session.isAutoCommit = false
|
session.isAutoCommit = false
|
||||||
session.isCommitedOrRollbacked = false
|
session.isCommitedOrRollbacked = false
|
||||||
session.tx = tx
|
session.tx = tx
|
||||||
|
|
||||||
session.saveLastSQL("BEGIN TRANSACTION")
|
session.saveLastSQL("BEGIN TRANSACTION")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -22,10 +29,23 @@ func (session *Session) Begin() error {
|
||||||
// Rollback When using transaction, you can rollback if any error
|
// Rollback When using transaction, you can rollback if any error
|
||||||
func (session *Session) Rollback() error {
|
func (session *Session) Rollback() error {
|
||||||
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
|
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
|
||||||
session.saveLastSQL(session.engine.dialect.RollBackStr())
|
session.saveLastSQL("ROLL BACK")
|
||||||
session.isCommitedOrRollbacked = true
|
session.isCommitedOrRollbacked = true
|
||||||
session.isAutoCommit = true
|
session.isAutoCommit = true
|
||||||
return session.tx.Rollback()
|
|
||||||
|
start := time.Now()
|
||||||
|
session.engine.logger.BeforeSQL(log.LogContext{
|
||||||
|
Ctx: session.ctx,
|
||||||
|
SQL: "ROLL BACK",
|
||||||
|
})
|
||||||
|
err := session.tx.Rollback()
|
||||||
|
session.engine.logger.AfterSQL(log.LogContext{
|
||||||
|
Ctx: session.ctx,
|
||||||
|
SQL: "ROLL BACK",
|
||||||
|
ExecuteTime: time.Now().Sub(start),
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -36,48 +56,61 @@ func (session *Session) Commit() error {
|
||||||
session.saveLastSQL("COMMIT")
|
session.saveLastSQL("COMMIT")
|
||||||
session.isCommitedOrRollbacked = true
|
session.isCommitedOrRollbacked = true
|
||||||
session.isAutoCommit = true
|
session.isAutoCommit = true
|
||||||
var err error
|
|
||||||
if err = session.tx.Commit(); err == nil {
|
|
||||||
// handle processors after tx committed
|
|
||||||
closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
|
|
||||||
if closuresPtr != nil {
|
|
||||||
for _, closure := range *closuresPtr {
|
|
||||||
closure(bean)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for bean, closuresPtr := range session.afterInsertBeans {
|
start := time.Now()
|
||||||
closureCallFunc(closuresPtr, bean)
|
session.engine.logger.BeforeSQL(log.LogContext{
|
||||||
|
Ctx: session.ctx,
|
||||||
if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
|
SQL: "COMMIT",
|
||||||
processor.AfterInsert()
|
})
|
||||||
}
|
err := session.tx.Commit()
|
||||||
}
|
if err != nil {
|
||||||
for bean, closuresPtr := range session.afterUpdateBeans {
|
return err
|
||||||
closureCallFunc(closuresPtr, bean)
|
|
||||||
|
|
||||||
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
|
|
||||||
processor.AfterUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for bean, closuresPtr := range session.afterDeleteBeans {
|
|
||||||
closureCallFunc(closuresPtr, bean)
|
|
||||||
|
|
||||||
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
|
|
||||||
processor.AfterDelete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
|
|
||||||
if len(*slices) > 0 {
|
|
||||||
*slices = make(map[interface{}]*[]func(interface{}), 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cleanUpFunc(&session.afterInsertBeans)
|
|
||||||
cleanUpFunc(&session.afterUpdateBeans)
|
|
||||||
cleanUpFunc(&session.afterDeleteBeans)
|
|
||||||
}
|
}
|
||||||
return err
|
session.engine.logger.AfterSQL(log.LogContext{
|
||||||
|
Ctx: session.ctx,
|
||||||
|
SQL: "COMMIT",
|
||||||
|
ExecuteTime: time.Now().Sub(start),
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
|
||||||
|
// handle processors after tx committed
|
||||||
|
closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
|
||||||
|
if closuresPtr != nil {
|
||||||
|
for _, closure := range *closuresPtr {
|
||||||
|
closure(bean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for bean, closuresPtr := range session.afterInsertBeans {
|
||||||
|
closureCallFunc(closuresPtr, bean)
|
||||||
|
|
||||||
|
if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
|
||||||
|
processor.AfterInsert()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for bean, closuresPtr := range session.afterUpdateBeans {
|
||||||
|
closureCallFunc(closuresPtr, bean)
|
||||||
|
|
||||||
|
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
|
||||||
|
processor.AfterUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for bean, closuresPtr := range session.afterDeleteBeans {
|
||||||
|
closureCallFunc(closuresPtr, bean)
|
||||||
|
|
||||||
|
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
|
||||||
|
processor.AfterDelete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
|
||||||
|
if len(*slices) > 0 {
|
||||||
|
*slices = make(map[interface{}]*[]func(interface{}), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cleanUpFunc(&session.afterInsertBeans)
|
||||||
|
cleanUpFunc(&session.afterUpdateBeans)
|
||||||
|
cleanUpFunc(&session.afterDeleteBeans)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue