您的位置 首页 知识

gorm 分页 Golang如何用gorm实现分页的功能 mongodbtemp

gorm 分页 Golang如何用gorm实现分页的功能 mongodbtemp

目录
  • 背景
  • go库下载
  • 初始化数据
    • 1建表
    • 2插入数据
    • 3查看数据
  • 4、代码示例
    • 1gorm结构体定义
    • 2分页结构体定义
    • 3封装分页技巧
    • 4封装获取数据库连接技巧
    • 5查询列表接口
    • 6启动http服务
    • 7调用获取列表接口
  • 拓展资料

    背景

    在提供列表接口时一般要用到分页,对于存储在某些数据库中的数据进行分页起来非常的方便,下文给出一个通过gorm进行分页并通过http返回数据的例子。

    go库下载

    gorm官方文档地址:https://gorm.io/zh_CN/docs/,库下载如下:

    go get -u gorm.io/gorm

    这篇文章小编将使用的数据库是mysql,因此要下载mysql驱动:

    go get -u gorm.io/driver/mysql

    这里使用gin框架来提供查询列表的接口想,库下载如下:

    go get -u github.com/gin-gonic/gin

    初始化数据

    1建表

    建一个用来测试分页的表,sql如下:

    CREATE TABLE test_page( id INT AUTO_INCREMENT PRIMARY KEY, number INT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ‘测试分页表’;

    2插入数据

    插入30条numbercreate_time字段不同的数据,sql如下:

    INSERT INTO test_page (number, create_time)VALUES (1, NOW() + INTERVAL 0 SECOND), (2, NOW() + INTERVAL 1 SECOND), (3, NOW() + INTERVAL 2 SECOND), (4, NOW() + INTERVAL 3 SECOND), (5, NOW() + INTERVAL 4 SECOND), (6, NOW() + INTERVAL 5 SECOND), (7, NOW() + INTERVAL 6 SECOND), (8, NOW() + INTERVAL 7 SECOND), (9, NOW() + INTERVAL 8 SECOND), (10, NOW() + INTERVAL 9 SECOND), (11, NOW() + INTERVAL 10 SECOND), (12, NOW() + INTERVAL 11 SECOND), (13, NOW() + INTERVAL 12 SECOND), (14, NOW() + INTERVAL 13 SECOND), (15, NOW() + INTERVAL 14 SECOND), (16, NOW() + INTERVAL 15 SECOND), (17, NOW() + INTERVAL 16 SECOND), (18, NOW() + INTERVAL 17 SECOND), (19, NOW() + INTERVAL 18 SECOND), (20, NOW() + INTERVAL 19 SECOND), (21, NOW() + INTERVAL 20 SECOND), (22, NOW() + INTERVAL 21 SECOND), (23, NOW() + INTERVAL 22 SECOND), (24, NOW() + INTERVAL 23 SECOND), (25, NOW() + INTERVAL 24 SECOND), (26, NOW() + INTERVAL 25 SECOND), (27, NOW() + INTERVAL 26 SECOND), (28, NOW() + INTERVAL 27 SECOND), (29, NOW() + INTERVAL 28 SECOND), (30, NOW() + INTERVAL 29 SECOND);

    3查看数据

    查看创建出来的30条数据:

    mysql [xxx]> select from test_page;+—-+——–+———————+———————+| id | number | create_time | update_time |+—-+——–+———————+———————+| 1 | 1 | 2024-10-21 07:11:19 | 2024-10-21 07:11:19 || 2 | 2 | 2024-10-21 07:11:20 | 2024-10-21 07:11:19 || 3 | 3 | 2024-10-21 07:11:21 | 2024-10-21 07:11:19 || 4 | 4 | 2024-10-21 07:11:22 | 2024-10-21 07:11:19 || 5 | 5 | 2024-10-21 07:11:23 | 2024-10-21 07:11:19 || 6 | 6 | 2024-10-21 07:11:24 | 2024-10-21 07:11:19 || 7 | 7 | 2024-10-21 07:11:25 | 2024-10-21 07:11:19 || 8 | 8 | 2024-10-21 07:11:26 | 2024-10-21 07:11:19 || 9 | 9 | 2024-10-21 07:11:27 | 2024-10-21 07:11:19 || 10 | 10 | 2024-10-21 07:11:28 | 2024-10-21 07:11:19 || 11 | 11 | 2024-10-21 07:11:29 | 2024-10-21 07:11:19 || 12 | 12 | 2024-10-21 07:11:30 | 2024-10-21 07:11:19 || 13 | 13 | 2024-10-21 07:11:31 | 2024-10-21 07:11:19 || 14 | 14 | 2024-10-21 07:11:32 | 2024-10-21 07:11:19 || 15 | 15 | 2024-10-21 07:11:33 | 2024-10-21 07:11:19 || 16 | 16 | 2024-10-21 07:11:34 | 2024-10-21 07:11:19 || 17 | 17 | 2024-10-21 07:11:35 | 2024-10-21 07:11:19 || 18 | 18 | 2024-10-21 07:11:36 | 2024-10-21 07:11:19 || 19 | 19 | 2024-10-21 07:11:37 | 2024-10-21 07:11:19 || 20 | 20 | 2024-10-21 07:11:38 | 2024-10-21 07:11:19 || 21 | 21 | 2024-10-21 07:11:39 | 2024-10-21 07:11:19 || 22 | 22 | 2024-10-21 07:11:40 | 2024-10-21 07:11:19 || 23 | 23 | 2024-10-21 07:11:41 | 2024-10-21 07:11:19 || 24 | 24 | 2024-10-21 07:11:42 | 2024-10-21 07:11:19 || 25 | 25 | 2024-10-21 07:11:43 | 2024-10-21 07:11:19 || 26 | 26 | 2024-10-21 07:11:44 | 2024-10-21 07:11:19 || 27 | 27 | 2024-10-21 07:11:45 | 2024-10-21 07:11:19 || 28 | 28 | 2024-10-21 07:11:46 | 2024-10-21 07:11:19 || 29 | 29 | 2024-10-21 07:11:47 | 2024-10-21 07:11:19 || 30 | 30 | 2024-10-21 07:11:48 | 2024-10-21 07:11:19 |+—-+——–+———————+———————+

    4、代码示例

    1gorm结构体定义

    可以根据在线sql转go结构体来实现,转换之后如下:

    package modelsimport ( “time”)type TestPage struct Id int `gorm:”column:id;type:int(11);AUTO_INCREMENT;primary_key” json:”id”` Number int `gorm:”column:number;type:int(11);NOT NULL” json:”number”` CreateTime time.Time `gorm:”column:create_time;type:datetime;default:CURRENT_TIMESTAMP” json:”create_time”` UpdateTime time.Time `gorm:”column:update_time;type:datetime;default:CURRENT_TIMESTAMP” json:”update_time”`}func (m TestPage) TableName() string return “test_page”}

    2分页结构体定义

    package typesimport “GoTest/gorm_demo/models”type PageReq struct Page int `form:”page,default=1″` PageSize int `form:”page_size,default=4″`}type PageResult struct TotalPage int `json:”total_page”` //总页数 TotalCount int `json:”total_count”` //总条数 Page int `json:”page”` //当前页 PageSize int `json:”page_size”` //当前页数据量 PrevPage bool `json:”prev_page”` //是否存在上页 NextPage bool `json:”next_page”` //是否存在下页}//要测试的分页结构type TestPageResp struct PageResult List []models.TestPage `json:”list”`}

    3封装分页技巧

    package pageimport ( “math” “GoTest/gorm_demo/types”)// GetOffsetAndLimit//// @Description: 获取查数据库的偏移量和限制数// @param page 当前页// @param pageSize 业数据量// @return offset 数据库偏移// @return limit 数据库限制量func GetOffsetAndLimit(page, pageSize int) (offset, limit int) limit = pageSize if limit <= 0 limit = 4 } if page > 1 offset = (page – 1) limit } return}// GetPageResult//// @Description: 获取分页结局// @param pg 当前页// @param pageSize 页数据量// @param totalCount 根据此数量进行分页// @return types.PageResult 分页结构func GetPageResult(pg, pageSize, totalCount int) types.PageResult res := types.PageResult} res.TotalCount = totalCount res.PageSize = pageSize res.Page = pg if pageSize > 0 && totalCount > 0 res.TotalPage = int(math.Ceil(float64(totalCount) / float64(pageSize))) } if res.Page < res.TotalPage res.NextPage = true } if res.Page > 1 res.PrevPage = true } return res}

    4封装获取数据库连接技巧

    使用gorm连接mysql

    package connimport ( “fmt” “runtime” “sync” “time” “GoTest/comm/logger” “go.uber.org/zap” “gorm.io/driver/mysql” “gorm.io/gorm” gormLog “gorm.io/gorm/logger”)type MysqlDb stringconst ( Xxx MysqlDb = “xxx”)var ( mysqlConn = map[MysqlDb]gorm.DB} mysqlLock = sync.RWMutex})func GetXxxDbConn() gorm.DB return getDbPool(Xxx)}func getDbPool(dbKey MysqlDb) gorm.DB mysqlLock.RLock() if conn, ok := mysqlConn[dbKey]; ok mysqlLock.RUnlock() return conn } mysqlLock.RUnlock() mysqlLock.Lock() defer mysqlLock.Unlock() var dsn string switch dbKey case Xxx: dsn = fmt.Sprintf(“%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=5s”, “xxx”, “xxx”, “127.0.0.1:3306”, “xxx”) default: logger.Error(“unknown db”, zap.String(“db”, string(dbKey))) return nil } conn := newConnect(dsn) mysqlConn[dbKey] = conn return conn}func newConnect(dsn string) gorm.DB conn, err := gorm.Open(mysql.Open(dsn), &gorm.Config Logger: gormLog.Default.LogMode(gormLog.Info), }) if err != nil logger.Error(“connect mysql error”, zap.String(“dsn”, dsn), zap.Error(err)) return nil } dbPool, err := conn.DB() if err != nil logger.Error(“get mysql db error”, zap.String(“dsn”, dsn), zap.Error(err)) return nil } logger.Info(“conn mysql success”) //连接池中中最大空闲时刻 dbPool.SetConnMaxIdleTime(time.Hour) //连接池中空闲连接的最大数量 dbPool.SetMaxIdleConns(runtime.NumCPU() 5) //数据库连接的最大数量 dbPool.SetMaxOpenConns(runtime.NumCPU() 10) //连接可复用最大时刻 dbPool.SetConnMaxLifetime(time.Hour 24) return conn}

    使用时只需要调用GetXxxDbConn函数获取连接即可。

    5查询列表接口

    使用gin框架启动一个http服务,并注册一条路由用于查询列表接口:

    r := gin.New() r.GET(“/page/list”, GetPageListHandler) if err := r.Run(“:8888”); err != nil panic(err) }

    查询列表接口回调函数实现如下:

    func GetPageListHandler(c gin.Context) var req types.PageReq if err := c.ShouldBind(&req); err != nil logger.Error(“invalid req”, zap.Error(err)) c.String(500, “invalid req”) return } logger.Info(“get page list req”, zap.Any(“req”, req)) db := conn.GetXxxDbConn() resp := types.TestPageResp} resp.List = make([]models.TestPage, 0) //获取所有数量 var count int64 if err := db.Model(&models.TestPage}).Count(&count).Error; err != nil logger.Error(“get count error”, zap.Error(err)) c.String(500, “get count error”) return } //计算分页数据 resp.PageResult = page.GetPageResult(req.Page, req.PageSize, int(count)) //计算偏移量 offset, limit := page.GetOffsetAndLimit(req.Page, req.PageSize) //数据库查询 if err := db.Model(&models.TestPage}).Order(“create_time DESC”).Offset(offset).Limit(limit).Find(&resp.List).Error; err != nil logger.Error(“get list error”, zap.Error(err)) c.String(500, “get list error”) return } //返回数据 c.JSON(http.StatusOK, resp)}

    6启动http服务

    控制台输出如下:

    [GIN-debug] [WARNING] Running in “debug” mode. Switch to “release” mode in production. – using env: export GIN_MODE=release – using code: gin.SetMode(gin.ReleaseMode)[GIN-debug] GET /page/list –> main.GetPageListHandler (1 handlers)[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.Please check https://pkg.go.dev/github.com/gin-gonic/ginreadme-don-t-trust-all-proxies for details.[GIN-debug] Listening and serving HTTP on :8888

    这里使用的是gin框架的debug模式,生产环境中不要用gin框架的debug模式,会影响程序的qps

    7调用获取列表接口

    使用curl命令来调用,获取第2页,页数据量为6条的数据,控制台输出如下:

    [xxx@xxx ~] curl -v -X GET –location “http://127.0.0.1:8888/page/list?page=2&page_size=6” About to connect() to 127.0.0.1 port 8888 (0) Trying 127.0.0.1… Connected to 127.0.0.1 (127.0.0.1) port 8888 (0)> GET /page/list?page=2&page_size=6 HTTP/1.1> User-Agent: curl/7.29.0> Host: 127.0.0.1:8888> Accept: /> < HTTP/1.1 200 OK< Content-Type: application/json; charset=utf-8< Date: Mon, 21 Oct 2024 09:23:13 GMT< Content-Length: 735< Connection 0 to host 127.0.0.1 left intact “total_page”: 5, //总共有5页 “total_count”: 30, //根据30条数据进行分页 “page”: 2, //当前页为第2页 “page_size”: 6, //每一页的大致为6 “prev_page”: true, //上一页存在 “next_page”: true, //下一页存在 “list”: [ //根据创建时刻倒序的列表 “id”: 24, “number”: 24, “create_time”: “2024-10-21T07:11:42+08:00”, “update_time”: “2024-10-21T07:11:19+08:00” }, “id”: 23, “number”: 23, “create_time”: “2024-10-21T07:11:41+08:00”, “update_time”: “2024-10-21T07:11:19+08:00” }, “id”: 22, “number”: 22, “create_time”: “2024-10-21T07:11:40+08:00”, “update_time”: “2024-10-21T07:11:19+08:00” }, “id”: 21, “number”: 21, “create_time”: “2024-10-21T07:11:39+08:00”, “update_time”: “2024-10-21T07:11:19+08:00” }, “id”: 20, “number”: 20, “create_time”: “2024-10-21T07:11:38+08:00”, “update_time”: “2024-10-21T07:11:19+08:00” }, “id”: 19, “number”: 19, “create_time”: “2024-10-21T07:11:37+08:00”, “update_time”: “2024-10-21T07:11:19+08:00” } ]}

    此时gin程序控制台输出:

    [GIN-debug] [WARNING] Running in “debug” mode. Switch to “release” mode in production. – using env: export GIN_MODE=release – using code: gin.SetMode(gin.ReleaseMode)[GIN-debug] GET /page/list –> main.GetPageListHandler (1 handlers)[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.Please check https://pkg.go.dev/github.com/gin-gonic/ginreadme-don-t-trust-all-proxies for details.[GIN-debug] Listening and serving HTTP on :8888[2024-10-21 17:23:13.435] | INFO | Goroutine:34 | [gorm_demo/main.go:131] | get page list req | “req”: “Page”:2,”PageSize”:6}} //分页请求数据[2024-10-21 17:23:13.437] | INFO | Goroutine:34 | [conn/mysql.go:74] | conn mysql success2024/10/21 17:23:13 D:/GoTest/gorm_demo/main.go:139[0.640ms] [rows:1] SELECT count() FROM `test_page` //查询所有数量的sql2024/10/21 17:23:13 D:/GoTest/gorm_demo/main.go:152[0.325ms] [rows:6] SELECT FROM `test_page` ORDER BY create_time DESC LIMIT 6 OFFSET 6 //根据分页请求计算出的偏移位置和限制量sql

    上面打印了gorm库中的日志信息,可以通过自定义zap对象来实现gormlogger对象来自定义gorm输出日志。

    拓展资料

    分页的技巧有很多,上面只是给出了其中一种,根据自己项目的业务场景选择一种最喜欢的技巧就行。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。

    无论兄弟们可能感兴趣的文章:

    • Golang开发使用gorm时打印SQL语句方式
    • GolangGorm实现自定义多态模型关联查询
    • Golang使用gorm实现分页功能的示例代码
    • Golang创建第一个web项目(Gin+Gorm)
    • Golang实现自定义时刻结构体并支持Json&Gorm

    返回顶部