zoukankan      html  css  js  c++  java
  • go语言web开发系列之十六:gin框架中通过gorm使用事务

    一,演示项目的相关信息

    1,地址:

    https://github.com/liuhongdi/digv16

    2,功能:以下订单为例,演示了在gorm中启用事务

    3, 项目结构:如图:

    说明:刘宏缔的go森林是一个专注golang的博客,
              地址:https://blog.csdn.net/weixin_43881017

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,数据库及sql

    1,数据表:

    2,建表sql:

    1.  
      CREATE TABLE `m_goods` (
    2.  
      `goodsId` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '商品id',
    3.  
      `goodsName` varchar(200) NOT NULL DEFAULT '' COMMENT '商品名称',
    4.  
      `stock` int unsigned NOT NULL DEFAULT '0' COMMENT '库存数量',
    5.  
      PRIMARY KEY (`goodsId`)
    6.  
      ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品表'
    1.  
      CREATE TABLE `m_order` (
    2.  
      `orderId` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '订单id',
    3.  
      `userId` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
    4.  
      `salePrice` decimal(10,0) NOT NULL DEFAULT '0' COMMENT '订单金额',
    5.  
      PRIMARY KEY (`orderId`),
    6.  
      KEY `userId` (`userId`)
    7.  
      ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单表'
    1.  
      CREATE TABLE `m_order_goods` (
    2.  
      `ogId` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
    3.  
      `orderId` bigint unsigned NOT NULL COMMENT '订单id',
    4.  
      `goodsId` bigint unsigned NOT NULL COMMENT '商品id',
    5.  
      `buyNum` int unsigned NOT NULL COMMENT '购买数量',
    6.  
      PRIMARY KEY (`ogId`),
    7.  
      UNIQUE KEY `orderId_2` (`orderId`,`goodsId`)
    8.  
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单商品表'

    3,插入一条演示数据:

    1.  
      INSERT INTO `m_goods` (`goodsId`, `goodsName`, `stock`) VALUES
    2.  
      (1, '施丹兰蜂蜜牛奶手工皂', 10);

    三,go代码说明

    1,controller/orderController.go

    1.  
      package controller
    2.  
       
    3.  
      import (
    4.  
      "fmt"
    5.  
      "github.com/gin-gonic/gin"
    6.  
      "github.com/liuhongdi/digv16/global"
    7.  
      "github.com/liuhongdi/digv16/service"
    8.  
      )
    9.  
       
    10.  
      type OrderController struct{}
    11.  
       
    12.  
      //result:= global.NewResult(c)
    13.  
       
    14.  
      func NewOrderController() OrderController {
    15.  
      return OrderController{}
    16.  
      }
    17.  
       
    18.  
      //新加一个订单
    19.  
      func (o *OrderController) AddOne(c *gin.Context) {
    20.  
      result := global.NewResult(c)
    21.  
       
    22.  
      goodsId:=1;
    23.  
      buyNum:=11;
    24.  
       
    25.  
      orderOne,err := service.AddOneOrder(int64(goodsId),buyNum);
    26.  
      if err != nil {
    27.  
      result.Error(404,"数据处理错误")
    28.  
      } else {
    29.  
      result.Success(&orderOne);
    30.  
      }
    31.  
      return
    32.  
      }
    33.  
       
    34.  
       
    35.  
      //新加一个订单,使用tx
    36.  
      func (o *OrderController) AddOneTx(c *gin.Context) {
    37.  
      result := global.NewResult(c)
    38.  
      goodsId:=1;
    39.  
      buyNum:=11;
    40.  
       
    41.  
      orderOne,err := service.AddOneOrderTx(int64(goodsId),buyNum);
    42.  
       
    43.  
      fmt.Println("orderOne:");
    44.  
      fmt.Println(orderOne);
    45.  
      fmt.Println(":end:");
    46.  
      //if ()
    47.  
      if (orderOne == nil || err != nil) {
    48.  
      result.Error(20001,"数据处理错误")
    49.  
      } else {
    50.  
      result.Success(&orderOne);
    51.  
      }
    52.  
      return
    53.  
      }

    2,service/order.go

    1.  
      package service
    2.  
       
    3.  
      import (
    4.  
      "github.com/liuhongdi/digv16/dao"
    5.  
      "github.com/liuhongdi/digv16/model"
    6.  
      )
    7.  
       
    8.  
      //新加一个订单
    9.  
      func AddOneOrder(goodsId int64,buyNum int) (*model.Order, error) {
    10.  
      return dao.AddOneOrder(goodsId,buyNum)
    11.  
      }
    12.  
       
    13.  
      //新加一个订单,使用tx
    14.  
      func AddOneOrderTx(goodsId int64,buyNum int) (*model.Order, error) {
    15.  
      return dao.AddOneOrderTx(goodsId,buyNum)
    16.  
      }

    3,dao/order.go

    1.  
      package dao
    2.  
       
    3.  
      import (
    4.  
      "errors"
    5.  
      "fmt"
    6.  
      "github.com/liuhongdi/digv16/global"
    7.  
      "github.com/liuhongdi/digv16/model"
    8.  
      "gorm.io/gorm"
    9.  
      )
    10.  
       
    11.  
      //添加一个订单
    12.  
      func AddOneOrder(goodsId int64,buyNum int) (*model.Order, error) {
    13.  
      //添加order
    14.  
      order := model.Order{UserId: 1, SalePrice: "20.00"}
    15.  
      resultCO := global.DBLink.Create(&order) // 通过数据的指针来创建
    16.  
      if (resultCO.Error != nil) {
    17.  
      return nil,resultCO.Error
    18.  
      }
    19.  
      //减库存
    20.  
      result := global.DBLink.Debug().Table("m_goods").Where("goodsId = ? and stock >= ?", goodsId,buyNum).Update("stock", gorm.Expr("stock - ?", buyNum))
    21.  
      if (result.Error != nil) {
    22.  
      return nil,result.Error
    23.  
      }
    24.  
      if (result.RowsAffected <= 0){
    25.  
      return nil,errors.New("减库存失败")
    26.  
      }
    27.  
      //添加订单商品
    28.  
      orderId := order.OrderId;
    29.  
      orderGoods := model.OrderGoods{OrderId:orderId,GoodsId:goodsId,BuyNum:buyNum}
    30.  
      resultCOG := global.DBLink.Create(&orderGoods) // 通过数据的指针来创建
    31.  
      if (resultCOG.Error != nil) {
    32.  
      return nil,resultCOG.Error
    33.  
      }
    34.  
      //return
    35.  
      return &order,nil
    36.  
      }
    37.  
       
    38.  
       
    39.  
      //添加一个订单
    40.  
      func AddOneOrderTx(goodsId int64,buyNum int) (*model.Order, error) {
    41.  
      // 事务开始后,需要使用 tx 处理数据
    42.  
      tx := global.DBLink.Begin()
    43.  
       
    44.  
      defer func() {
    45.  
      if r := recover(); r != nil {
    46.  
      fmt.Println("this is in defer recover")
    47.  
      tx.Rollback()
    48.  
      }
    49.  
      }()
    50.  
       
    51.  
      if err := tx.Error; err != nil {
    52.  
      return nil,err
    53.  
      }
    54.  
       
    55.  
      //添加order
    56.  
      order := model.Order{UserId: 1, SalePrice: "20.00"}
    57.  
      resultCO := tx.Debug().Create(&order) // 通过数据的指针来创建
    58.  
      if (resultCO.Error != nil) {
    59.  
      tx.Rollback()
    60.  
      return nil,resultCO.Error
    61.  
      }
    62.  
       
    63.  
      /*
    64.  
      var z int = 0
    65.  
      var i int = 100 / z
    66.  
      fmt.Println("i:%i",i)
    67.  
      */
    68.  
      //减库存
    69.  
      result := tx.Debug().Table("m_goods").Where("goodsId = ? and stock >= ?", goodsId,buyNum).Update("stock", gorm.Expr("stock - ?", buyNum))
    70.  
      if (result.Error != nil) {
    71.  
      tx.Rollback()
    72.  
      return nil,result.Error
    73.  
      }
    74.  
      if (result.RowsAffected <= 0){
    75.  
      tx.Rollback()
    76.  
      fmt.Println("减库存失败")
    77.  
      return nil,errors.New("减库存失败")
    78.  
      }
    79.  
      //添加订单商品
    80.  
      orderId := order.OrderId;
    81.  
      orderGoods := model.OrderGoods{OrderId:orderId,GoodsId:goodsId,BuyNum:buyNum}
    82.  
      resultCOG := tx.Debug().Create(&orderGoods) // 通过数据的指针来创建
    83.  
      if (resultCOG.Error != nil) {
    84.  
      tx.Rollback()
    85.  
      return nil,resultCOG.Error
    86.  
      }
    87.  
      //commit
    88.  
      fmt.Println("begin commit")
    89.  
      errCM := tx.Commit().Error
    90.  
      if (errCM != nil) {
    91.  
      fmt.Println("begin return1")
    92.  
      tx.Rollback()
    93.  
      return nil,errCM
    94.  
      }else {
    95.  
      fmt.Println("begin return2")
    96.  
      return &order,nil
    97.  
      }
    98.  
      }

    4,model/goods.go

    1.  
      package model
    2.  
       
    3.  
      type Goods struct {
    4.  
      GoodsId int64 `gorm:"column:goodsId",json:"goodsId"` // 自增
    5.  
      GoodsName string `gorm:"column:goodsName",json:"goodsName"` // 用户id
    6.  
      Stock int `gorm:"column:stock",json:"stock"` // 售价
    7.  
      }
    8.  
       
    9.  
      func (Goods) TableName() string {
    10.  
      return "m_goods"
    11.  
      }

    5,model/order.go

    1.  
      package model
    2.  
       
    3.  
      type Order struct {
    4.  
      OrderId int64 `gorm:"primaryKey;autoIncrement;column:orderId",json:"orderid"` // 自增
    5.  
      UserId int64 `gorm:"column:userId",json:"userid"` // 用户id
    6.  
      SalePrice string `gorm:"column:salePrice",json:"saleprice"` // 售价
    7.  
      }
    8.  
       
    9.  
      func (Order) TableName() string {
    10.  
      return "m_order"
    11.  
      }

    6,router/router.go

    1.  
      package router
    2.  
       
    3.  
      import (
    4.  
      "github.com/gin-gonic/gin"
    5.  
      "github.com/liuhongdi/digv16/controller"
    6.  
      "github.com/liuhongdi/digv16/global"
    7.  
      "log"
    8.  
      "runtime/debug"
    9.  
      )
    10.  
       
    11.  
      func Router() *gin.Engine {
    12.  
      router := gin.Default()
    13.  
      //处理异常
    14.  
      router.NoRoute(HandleNotFound)
    15.  
      router.NoMethod(HandleNotFound)
    16.  
      router.Use(Recover)
    17.  
       
    18.  
      // 路径映射
    19.  
      goodsc:=controller.NewGoodsController()
    20.  
      router.GET("/goods/getone/:id", goodsc.GetOne);
    21.  
      //router.GET("/article/list", articlec.GetList);
    22.  
       
    23.  
      orderc:=controller.NewOrderController()
    24.  
      router.GET("/order/addone", orderc.AddOne);
    25.  
      router.GET("/order/addonetx", orderc.AddOneTx);
    26.  
       
    27.  
      return router
    28.  
      }
    29.  
       
    30.  
      func HandleNotFound(c *gin.Context) {
    31.  
      global.NewResult(c).Error(404,"资源未找到")
    32.  
      return
    33.  
      }
    34.  
       
    35.  
      func Recover(c *gin.Context) {
    36.  
      defer func() {
    37.  
      if r := recover(); r != nil {
    38.  
      //打印错误堆栈信息
    39.  
      log.Printf("panic: %v ", r)
    40.  
      debug.PrintStack()
    41.  
      global.NewResult(c).Error(500,"服务器内部错误")
    42.  
      }
    43.  
      }()
    44.  
      //加载完 defer recover,继续后续接口调用
    45.  
      c.Next()
    46.  
      }

    7,其他相关代码可访问github查看

    四,测试效果

    1,测试除0错:

    访问:

    http://127.0.0.1:8080/order/addonetx

       返回:

    2,测试扣减库存出错

    把dao/order.go中,

    AddOneOrderTx方法中的除0错代码注释掉

    1.  
      /*
    2.  
      var z int = 0
    3.  
      var i int = 100 / z
    4.  
      fmt.Println("i:%i",i)
    5.  
      */

    再次执行:访问:

    http://127.0.0.1:8080/order/addonetx

    可以从控制台看到输出的提示:

    1.  
      2021/01/13 13:32:25 /data/liuhongdi/digv16/dao/order.go:69
    2.  
      [2.219ms] [rows:0] UPDATE `m_goods` SET `stock`=stock - 11 WHERE goodsId = 1 and stock >= 11
    3.  
      减库存失败

    3,测试正常执行事务成功

    把controller/orderController.go中,

    AddOneTx方法,把buyNum的值改为9

    buyNum:=9

    再次执行:

    http://127.0.0.1:8080/order/addonetx

    返回:

    事务执行已成功

    五,使用的库的版本:

    1.  
      module github.com/liuhongdi/digv16
    2.  
       
    3.  
      go 1.15
    4.  
       
    5.  
      require (
    6.  
      github.com/gin-gonic/gin v1.6.3
    7.  
      github.com/jinzhu/gorm v1.9.16 // indirect
    8.  
      gorm.io/driver/mysql v1.0.1
    9.  
      gorm.io/gorm v1.20.6
    10.  
      )
  • 相关阅读:
    程序员无休止加班的真正原因!
    Tomcat 爆出高危漏洞!
    Spring Boot 2.3 终于要来了!
    2020 年 4月全国程序员工资出炉!
    面试官再问你如何看待义务加班,学会如何怼回去!
    如何在一分钟内搞定面试官?
    安装android studio时,解决unable to access android sdk add-on list
    poj 3230 Travel(dp)
    hdu 2059 龟兔赛跑(dp)
    解决未能启动服务“VMware Authorization Service”
  • 原文地址:https://www.cnblogs.com/ExMan/p/14312276.html
Copyright © 2011-2022 走看看