From 73a23aef4aaf699835415c42377b39e9564cbb8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=AD=90=E9=93=AD?= Date: Fri, 21 Mar 2025 13:38:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E6=9E=B7=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 1 + go.sum | 10 ++++- internal/biz/cmb.go | 78 +++++++++++++++++--------------------- internal/data/gorm_test.go | 75 ++++++++++++++++++++++++++++++------ internal/pkg/helper/ctx.go | 18 +++++++++ internal/service/cmb.go | 10 ++--- 6 files changed, 130 insertions(+), 62 deletions(-) create mode 100644 internal/pkg/helper/ctx.go diff --git a/go.mod b/go.mod index ac2a560..8bff135 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/mysql v1.5.7 gorm.io/gorm v1.25.12 + gorm.io/hints v1.1.2 ) require ( diff --git a/go.sum b/go.sum index 7958fd3..be9fccb 100644 --- a/go.sum +++ b/go.sum @@ -128,7 +128,6 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -184,6 +183,9 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -461,9 +463,15 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c= +gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I= +gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o= +gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= diff --git a/internal/biz/cmb.go b/internal/biz/cmb.go index cdd40a4..c77543f 100644 --- a/internal/biz/cmb.go +++ b/internal/biz/cmb.go @@ -13,49 +13,49 @@ import ( func (v *VoucherBiz) CmbOrder(ctx context.Context, req *bo.OrderCreateReqBo) (orderNo string, err error) { - ctx, cancel := context.WithTimeout(ctx, 25*time.Second) - defer cancel() + c := vo.CmbOrderLockKey.BuildCache([]string{req.OutBizNo, req.Type.String()}) - //c := vo.CmbOrderLockKey.BuildCache([]string{req.OutBizNo, req.Type.String()}) + err = lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error { - //err = lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error { + order, err := v.OrderRepo.GetByOutBizNo(ctx, vo.OrderTypeCmb, req.OutBizNo) - order, err := v.OrderRepo.GetByOutBizNo(ctx, vo.OrderTypeCmb, req.OutBizNo) + if err != nil && !err2.IsDbNotFound(err) { + return err + } - if err != nil && !err2.IsDbNotFound(err) { - return orderNo, err - } + if order != nil { - if order != nil { + if order.Status.IsFail() { - if order.Status.IsFail() { - - if err = v.orderRetry(ctx, order); err != nil { - return orderNo, err + if err = v.orderRetry(ctx, order); err != nil { + return err + } } + + orderNo = order.OrderNo + return nil + } + + product, err := v.ProductRepo.GetByProductNo(ctx, req.ProductNo) + if err != nil { + return err + } + + if !product.Channel.IsWeChat() { + return err2.ErrorCmbProductNotSupported("只支持微信") + } + + order, err = v.order(ctx, req, product) + if err != nil { + return err } orderNo = order.OrderNo - return orderNo, err - } - product, err := v.ProductRepo.GetByProductNo(ctx, req.ProductNo) - if err != nil { - return orderNo, err - } + return nil + }) - if !product.Channel.IsWeChat() { - return orderNo, err2.ErrorCmbProductNotSupported("只支持微信") - } - - order, err = v.order(ctx, req, product) - if err != nil { - return orderNo, err - } - - orderNo = order.OrderNo - - return orderNo, nil + return } func (v *VoucherBiz) CmbQuery(ctx context.Context, orderNo string) (resp *v1.CmbQueryReply, err error) { @@ -130,29 +130,19 @@ func (v *VoucherBiz) CmbProductQuery(ctx context.Context, productNo string) (rep inputFormat := time.RFC3339 if wechatResp.AvailableBeginTime != nil { - // 解析开始时间 availableBeginTime, _ := time.Parse(inputFormat, *wechatResp.AvailableBeginTime) reps.StartTime = availableBeginTime.Format(time.DateTime) reps.SaleStartTime = reps.StartTime + + reps.SaleStartTime = reps.StartTime } if wechatResp.AvailableEndTime != nil { - // 解析结束时间 availableEndTime, _ := time.Parse(inputFormat, *wechatResp.AvailableEndTime) reps.EndTime = availableEndTime.Format(time.DateTime) reps.SaleEndTime = reps.EndTime - } - if wechatResp.StartTime != nil { - // 批次激活开启时间 - s, _ := time.Parse(inputFormat, *wechatResp.StartTime) - reps.SaleStartTime = s.Format(time.DateTime) - } - - if wechatResp.StopTime != nil { - // 批次永久停止时间 - e, _ := time.Parse(inputFormat, *wechatResp.StopTime) - reps.SaleEndTime = e.Format(time.DateTime) + reps.SaleEndTime = reps.EndTime } reps.Amount = fmt.Sprintf("%d", *wechatResp.StockUseRule.FixedNormalCoupon.CouponAmount) diff --git a/internal/data/gorm_test.go b/internal/data/gorm_test.go index ac9eedd..bf5357a 100644 --- a/internal/data/gorm_test.go +++ b/internal/data/gorm_test.go @@ -1,42 +1,52 @@ package data import ( + "context" "errors" "fmt" "google.golang.org/protobuf/types/known/durationpb" "gorm.io/gorm" + "gorm.io/hints" "sync" "testing" "time" + "voucher/internal/biz/vo" "voucher/internal/conf" "voucher/internal/data/model" ) -func Test_db(t *testing.T) { - maxLifetime := durationpb.New(300) // 5分钟 +func Test_gorm_db(t *testing.T) { data := &conf.Data_Database{ Driver: "mysql", - Source: "root:lansexiongdi6,@tcp(47.97.27.195:3306)/voucher?parseTime=True&loc=Local", - MaxIdle: 50, // 空闲连接池 - MaxOpen: 100, // 最大连接数 - MaxLifetime: maxLifetime, + Source: "root:lsxddb123.@tcp(47.108.53.72:3306)/voucher?parseTime=True&loc=Local", + MaxIdle: 20, // 空闲连接池 + MaxOpen: 200, // 最大连接数 + MaxLifetime: durationpb.New(60), // 5分钟 IsDebug: false, } gormDb, cleanup := db(data) defer cleanup() start2 := time.Now() + + concurrency := 10 // 调整并发数 errCount := 0 + var wg sync.WaitGroup - const concurrency = 2 // 调整并发数 wg.Add(concurrency) for i := 0; i < concurrency; i++ { - go func() { + go func(i int) { defer wg.Done() - var m model.Product - tx := gormDb.Model(model.Product{}).Where(model.Product{ProductNo: "000"}).First(&m) + ctx := context.Background() + var info model.Order + tx := gormDb. + WithContext(ctx). + Model(model.Order{}). + //Clauses(hints.UseIndex("udx_out_biz_no_type")). + Where(model.Order{Type: vo.OrderTypeCmb.GetValue(), OutBizNo: fmt.Sprintf("174252390990605ngywYrSAGE83e1%d", i)}). + First(&info) if tx.Error != nil { if errors.Is(tx.Error, gorm.ErrRecordNotFound) { t.Errorf("未找到记录") @@ -45,9 +55,50 @@ func Test_db(t *testing.T) { errCount += 1 } } - }() + }(i) } wg.Wait() - fmt.Printf("\n--------------连接请求,总请求耗时: %v,总数: %d, 失败次数: %d--------------\n", time.Since(start2), concurrency, errCount) + t.Logf("\n--------------连接请求,总请求耗时: %v,总数: %d, 失败次数: %d--------------\n", time.Since(start2), concurrency, errCount) +} + +func Test_db(t *testing.T) { + maxLifetime := durationpb.New(300) // 5分钟 + data := &conf.Data_Database{ + Driver: "mysql", + Source: "root:lansexiongdi6,@tcp(47.97.27.195:3306)/voucher?parseTime=True&loc=Local", + MaxIdle: 2, // 空闲连接池 + MaxOpen: 10, // 最大连接数 + MaxLifetime: maxLifetime, + IsDebug: false, + } + gormDb, cleanup := db(data) + defer cleanup() + + start2 := time.Now() + + errCount := 0 + const concurrency = 2 + + for i := 0; i < concurrency; i++ { + ctx := context.Background() + + var info model.Order + tx := gormDb. + WithContext(ctx). + Model(model.Order{}). + Clauses(hints.ForceIndex("udx_out_biz_no_type")). + Where(model.Order{Type: vo.OrderTypeCmb.GetValue(), OutBizNo: fmt.Sprintf("174252390990605ngywYrSAGE83e1%d", i)}). + First(&info) + if tx.Error != nil { + if errors.Is(tx.Error, gorm.ErrRecordNotFound) { + t.Errorf("未找到记录") + } else { + fmt.Printf("请求错误: %v\n", tx.Error) + errCount += 1 + } + } + } + + t.Logf("\n--------------连接请求,总请求耗时: %v,总数: %d, 失败次数: %d--------------\n", time.Since(start2), concurrency, errCount) } diff --git a/internal/pkg/helper/ctx.go b/internal/pkg/helper/ctx.go new file mode 100644 index 0000000..83495ba --- /dev/null +++ b/internal/pkg/helper/ctx.go @@ -0,0 +1,18 @@ +package helper + +import ( + "context" + "time" +) + +// valueOnlyContext 包装一个只有value的context +type valueOnlyContext struct{ context.Context } + +func (valueOnlyContext) Deadline() (deadline time.Time, ok bool) { return } +func (valueOnlyContext) Done() <-chan struct{} { return nil } +func (valueOnlyContext) Err() error { return nil } + +// CopyValueCtx 复制一个只有value的context +func CopyValueCtx(ctx context.Context) context.Context { + return valueOnlyContext{ctx} +} diff --git a/internal/service/cmb.go b/internal/service/cmb.go index cf9f9af..6a62854 100644 --- a/internal/service/cmb.go +++ b/internal/service/cmb.go @@ -77,6 +77,10 @@ func (s *VoucherService) CmbOrder(ctx http.Context) error { func (v *VoucherService) cmbOrder(ctx http.Context) (string, error) { + //var ctxCopy http.Context + + //copy(ctx, ctxCopy) + bodyBytes, err := io.ReadAll(ctx.Request().Body) if err != nil { return "", err2.ErrorCmbParamFail(err.Error()) @@ -184,11 +188,7 @@ func (s *VoucherService) CmbQuery(ctx http.Context) error { bizReply, err := s.cmbQuery(ctx) if err != nil { - //se := errors.FromError(err) - // - //if len(se.Reason) == 0 { - // se.Reason = err2.CmbErr_CMB_UNKNOWN.String() - //} + req.RespCode = vo.CmbResponseStatusFail.GetValue() req.RespMsg = err.Error() req.BizContent = ""