Golang使用gorm实现分页功能的示例代码

 更新时间:2024年10月22日 09:51:50   作者:在成都搬砖的鸭鸭  
在提供列表接口时一般要用到分页,对于存储在某些数据库中的数据进行分页起来非常的方便,下文给出一个通过gorm进行分页并通过http返回数据的例子,感兴趣的小伙帮跟着小编一起来看看吧

1、背景

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

2、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

3、初始化数据

【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、代码示例

【1】gorm结构体定义

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

package models

import (
	"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 types

import "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 page

import (
	"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】查询列表接口

使用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)
}

【5】启动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/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8888

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

【6】调用获取列表接口

使用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/gin#readme-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 success

2024/10/21 17:23:13 D:/GoTest/gorm_demo/main.go:139
[0.640ms] [rows:1] SELECT count(*) FROM `test_page`  //查询所有数量的sql

2024/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输出日志。

5、总结

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

到此这篇关于Golang使用gorm实现分页功能的示例代码的文章就介绍到这了,更多相关Golang gorm实现分页内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • GO语言中err接口及defer延迟异常处理分析

    GO语言中err接口及defer延迟异常处理分析

    这篇文章主要为大家介绍了GO语言中err接口及defer延迟异常处理的示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • Go语言怎么使用变长参数函数

    Go语言怎么使用变长参数函数

    本文主要介绍了Go语言怎么使用变长参数函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • go实现文件的创建、删除与读取示例代码

    go实现文件的创建、删除与读取示例代码

    这篇文章主要给大家介绍了关于go如何实现文件的创建、删除与读取的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧
    2019-02-02
  • Go语言中结构体的高级技巧分享

    Go语言中结构体的高级技巧分享

    这篇文章主要为大家分享一下Go语言中结构体的高级技巧,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-08-08
  • Go语言标准错误error全面解析

    Go语言标准错误error全面解析

    Go语言中的错误处理是通过内置的error接口来实现的,其中errorString和wrapError是两种常见的错误类型实现方式,errorString通过errors.New()方法实现,而wrapError则通过fmt.Errorf()方法实现,支持错误的嵌套和解析
    2024-10-10
  • go实现冒泡排序的示例代码

    go实现冒泡排序的示例代码

    这篇文章主要介绍了go实现冒泡排序的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Golang字符串常用函数的使用

    Golang字符串常用函数的使用

    Golang提供了许多内置的字符串函数,这些函数可在处理字符串数据时帮助执行一些操作,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • goland中文件头自动注释的操作

    goland中文件头自动注释的操作

    这篇文章主要介绍了goland中文件头自动注释的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go 语言单例模式示例详解

    Go 语言单例模式示例详解

    这篇文章主要为大家介绍了Go 语言单例模式示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • Golang学习之map的用法详解

    Golang学习之map的用法详解

    在Golang(又称Go语言)中,map是一种非常有用的数据结构,所以这篇文章小编就来带大家一起深入了解一下map的用法,感兴趣的小伙伴可以了解一下
    2023-06-06

最新评论