【Go】基于 Gin 从0到1搭建 Web 管理后台系统后端服务(二)连接数据库

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【Go】基于 Gin 从0到1搭建 Web 管理后台系统后端服务(二)连接数据库

image.png接下来,我将用几篇文章介绍如何基于 Go 语言搭建一个后端的基础架子。然后前后端同步进行开发,后端服务基于 Gin + Gorm + Casbin,前端则是基于 React + antd,开发一套常见的基于 RBAC 权限控制的前后端分离的全栈管理后台项目,手把手带你入门前后端开发。第一篇:

已经完成,接下来进入第二篇,将实现数据库连接:

image.png本文相关代码在:gin_common_web_server - branch:cha-02

1、什么是数据库?

这个问题可能对后端同学比较熟悉了,但是对大多数从未接触过后端开发的前端同学来说,可能只停留在了解它的阶段。数据库通常分为层次式数据库、网络式数据库和关系式数据库三种。而不同的数据库是按不同的数据结构来联系和组织的。而在当今的互联网中,最常见的数据库模型主要是两种,即关系型数据库和非关系型数据库。

数据库是一个可以很简单、但也可以很高深的领域,鉴于本系列的目的,下面只介绍几种常见的数据库分类及其使用场景:

image.png

  1. 关系型数据库适合存储结构化数据,比如用户的账号信息等:
  • 这些数据通常需要做结构化查询,比如 join,这时候关系型数据库就要略胜一筹
  • 这些数据的规模、增长的速度通常可以预期
  • 能保证数据的事务性、一致性要求
  1. 非关系型数据库适合存储非结构化数据,比如微博、博客文章、用户评论等:
  • 这些数据通常用于模糊处理,比如全文检索、机器学习
  • 这些数据是海量的,而且增长的速度是难以预期的
  • 通常是无限(至少接近)伸缩性的
  • 按key获取数据效率很高,但对join或其他结构化查询的支持就比较差

接下来,我们将在项目实现 Go 连接 MySQLPostgreSQL 这两种数据库。

2、Go 连接 MySQL

在本项目中,将使用 Gorm 作为 orm,它的特性(来自官方网站):

  • 全功能 ORM
  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 PreloadJoins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • Auto Migration
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

安装:

go get -u gorm.io/gorm 
go get -u gorm.io/driver/sqlite 

同时你还要保证你的电脑已经安装了MySQL数据库,具体的方法我就不详细介绍了,这都是基操了。这里给出两个链接大家自行安装:

2.1 定义MySQL配置

和之前的日志配置一样,在根目录下的 config.yaml 中定义好我们自定义的 MySQL 配置:

# ...
mysql: # MySQL 配置
  host: 127.0.0.1 # 服务器地址
  port: "3306" # 端口
  config: charset=utf8mb4&parseTime=True&loc=Local # 其他配置
  db_name: east_white_admin_server # 数据库名称
  username: root # 数据库用户名
  password: "123456" # 数据库密码
  prefix: "t_" # 全局表前缀,单独定义 TableName 则不生效
  singular: false # 是否开启全局禁用复数,true表示不开启
  engine: "" # 引擎,默认InnoDB
  max_idle_conns: 10 # 最大空闲连接数
  max_open_conns: 100 # 最大连接数
  log_mode: error # 日志级别
  log_zap: false # 是否通过zap写日志文件

接下来,需要用结构体对配置进行解析,然后将其挂载到全局变量上。在 config 下新建 gorm_mysql.go,定义如下的结构体:

package config
type MySQL struct {
   Host         string `mapstructure:"host" json:"host" yaml:"host"`                               // 服务器地址:端口
   Port         string `mapstructure:"port" json:"port" yaml:"port"`                               //:端口
   Config       string `mapstructure:"config" json:"config" yaml:"config"`                         // 高级配置
   Dbname       string `mapstructure:"db_name" json:"db_name" yaml:"db_name"`                      // 数据库名
   Username     string `mapstructure:"username" json:"username" yaml:"username"`                   // 数据库用户名
   Password     string `mapstructure:"password" json:"password" yaml:"password"`                   // 数据库密码
   Prefix       string `mapstructure:"prefix" json:"prefix" yaml:"prefix"`                         // 全局表前缀,单独定义TableName则不生效
   Singular     bool   `mapstructure:"singular" json:"singular" yaml:"singular"`                   // 是否开启全局禁用复数,true表示开启
   Engine       string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"`        // 数据库引擎,默认InnoDB
   MaxIdleConns int    `mapstructure:"max_idle_conns" json:"max_idle_conns" yaml:"max_idle_conns"` // 空闲中的最大连接数
   MaxOpenConns int    `mapstructure:"max_open_conns" json:"max_open_conns" yaml:"max_open_conns"` // 打开到数据库的最大连接数
   LogMode      string `mapstructure:"log_mode" json:"log_mode" yaml:"log_mode"`                   // 是否开启Gorm全局日志
   LogZap       bool   `mapstructure:"log_zap" json:"log_zap" yaml:"log_zap"`                      // 是否通过zap写入日志文件
}
func (m *MySQL) Dsn() string {
   return m.Username + ":" + m.Password + "@tcp(" + m.Host + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
}
func (m *MySQL) GetLogMode() string {
   return m.LogMode
}

解释一下里面为什么要定义 Dsn 这个方法:它用于返回一个 MySQL 连接的 DSN(数据源名称),包括用户名、密码、主机、端口、数据库以及其他配置信息。这个方法只能通过一个MySQL类型的实例进行调用,因此将其与该类型关联并使用(*MySQL)作为接收器来声明该函数。

这么做的好处是:将这个方法与MySQL 结构体 相关联可以更好地组织代码,并避免对外暴露不必要的细节和实现的复杂性。这还使得代码更加易于维护和扩展,因为它涉及到 MySQL 连接的所有信息都被封装在一个地方了,而不是散落在程序的各个地方。

同理 GetLogMode 方法也类似。

然后也需要和zap一样,将其统一配置在 config.go 中:

package config
type Configuration struct {
   App   App   `mapstructure:"app" json:"app" yaml:"app"`
   Zap   Zap   `mapstructure:"zap" json:"zap" yaml:"zap"`
   MySQL MySQL `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
}

2.2 挂载到全局

为什么要做这个看似多余的操作?随取随用不就好了吗?

*gorm.DB 挂载到全局变量中的原因是为了方便在整个应用程序中共享一个数据库连接,我们可以在项目的任何地方访问该数据库连接,从而避免了频繁地打开和关闭数据库连接的开销,这样可以提高数据库操作的效率和性能。此外,全局变量还可以方便地进行数据库连接的初始化和配置,以及对数据库操作的统一管理和处理。

需要注意的是,在使用全局变量时需要注意多个协程之间对全局变量的并发访问问题,应该使用互斥锁或其他的并发控制机制来确保全局变量的安全性和一致性。

package global
import (
   "ewa_admin_server/config"
   "go.uber.org/zap"
   "gorm.io/gorm"
   "github.com/spf13/viper"
)
var (
   EWA_CONFIG config.Configuration
   EWA_VIPER  *viper.Viper
   EWA_LOG    *zap.Logger
   EWA_DB     *gorm.DB
)

2.3 封装连接数据库方法

我们在根目录下新建一个 initialize 作为一些需要在程序启动时初始化的操作集合。在这个文件中新建 gorm_mysql.go 文件:

package initialize
import (
   "ewa_admin_server/global"
   "ewa_admin_server/initialize/internal"
   "fmt"
   "gorm.io/driver/mysql"
   "gorm.io/gorm"
)
// GormMysql 初始化Mysql数据库
func GormMysql() *gorm.DB {
   m := global.EWA_CONFIG.MySQL
   if m.Dbname == "" {
      return nil
   }
   // 创建 mysql.Config 实例,其中包含了连接数据库所需的信息,比如 DSN (数据源名称),字符串类型字段的默认长度以及自动根据版本进行初始化等参数。
   mysqlConfig := mysql.Config{
      DSN:                       m.Dsn(), // DSN data source name
      DefaultStringSize:         191,     // string 类型字段的默认长度
      SkipInitializeWithVersion: false,   // 根据版本自动配置
   }
   // 打开数据库连接
   db, err := gorm.Open(mysql.New(mysqlConfig), internal.Gorm.Config(m.Prefix, m.Singular))
   // 将引擎设置为我们配置的引擎,并设置每个连接的最大空闲数和最大连接数。
   if err != nil {
      return nil
   } else {
      db.InstanceSet("gorm:table_options", "ENGINE="+m.Engine)
      sqlDB, _ := db.DB()
      sqlDB.SetMaxIdleConns(m.MaxIdleConns)
      sqlDB.SetMaxOpenConns(m.MaxOpenConns)
      fmt.Println("====3-gorm====: gorm link mysql success")
      return db
   }
}

其中的 gorm 配置,我们抽离并封装成单独的方法了,因为后面其他的数据库连接也会使用到。

initialize/internal 中新建 gorm.go

package internal
import (
   "ewa_admin_server/global"
   "log"
   "os"
   "time"
   "gorm.io/gorm/schema"
   "gorm.io/gorm"
   "gorm.io/gorm/logger"
)
type DBBASE interface {
   GetLogMode() string
}
var Gorm = new(_gorm)
type _gorm struct{}
// Config gorm 自定义配置
func (g *_gorm) Config(prefix string, singular bool) *gorm.Config {
   // 将传入的字符串前缀和单复数形式参数应用到 GORM 的命名策略中,并禁用迁移过程中的外键约束,返回最终生成的 GORM 配置信息。
   config := &gorm.Config{
      // 命名策略
      NamingStrategy: schema.NamingStrategy{
         TablePrefix:   prefix,   // 表前缀,在表名前添加前缀,如添加用户模块的表前缀 user_
         SingularTable: singular, // 是否使用单数形式的表名,如果设置为 true,那么 User 模型会对应 users 表
      },
      // 是否在迁移时禁用外键约束,默认为 false,表示会根据模型之间的关联自动生成外键约束语句
      DisableForeignKeyConstraintWhenMigrating: true,
   }
   _default := logger.New(NewWriter(log.New(os.Stdout, "\r\n", log.LstdFlags)), logger.Config{
      SlowThreshold: 200 * time.Millisecond,
      LogLevel:      logger.Warn,
      Colorful:      true,
   })
   var logMode DBBASE
   switch global.EWA_CONFIG.App.DbType {
   case "mysql":
      logMode = &global.EWA_CONFIG.MySQL
   default:
      logMode = &global.EWA_CONFIG.MySQL
   }
   switch logMode.GetLogMode() {
   case "silent", "Silent":
      config.Logger = _default.LogMode(logger.Silent)
   case "error", "Error":
      config.Logger = _default.LogMode(logger.Error)
   case "warn", "Warn":
      config.Logger = _default.LogMode(logger.Warn)
   case "info", "Info":
      config.Logger = _default.LogMode(logger.Info)
   default:
      config.Logger = _default.LogMode(logger.Info)
   }
   return config
}

解释一下这里面的关键代码:

_default := logger.New(NewWriter(log.New(os.Stdout, "\r\n", log.LstdFlags)), logger.Config{
  SlowThreshold: 200 * time.Millisecond,
  LogLevel:      logger.Warn,
  Colorful:      true,
})

这段代码用于创建 GORM 框架的日志记录器,接受一个 io.Writer 类型的参数和一个 logger.Config 类型的配置项作为输入,返回一个 logger.Interface 类型的日志记录器:

  1. log.New(os.Stdout, "\r\n", log.LstdFlags):创建一个输出到标准输出(控制台)的标准 logger,使用 \r\n 作为换行符,打印格式包括日期和时间。
  2. logger.Config{SlowThreshold: 200 * time.Millisecond, LogLevel: logger.Warn, Colorful: true}:创建一个日志记录器的配置项,其中:
  • SlowThreshold 表示慢 SQL 的阈值,超过这个阈值的 SQL 将被视为慢 SQL,单位为毫秒。
  • LogLevel 表示日志级别,只记录级别不低于该值的日志,可选的值包括 Silent, Error, Warn, Info, TraceDebug,分别对应不输出日志、输出错误日志、输出警告及以上级别的日志、输出信息及以上级别的日志、输出所有日志和输出调试日志。
  • Colorful 表示是否启用彩色日志输出。

主要是创建一个 GORM 框架的日志记录器,并将日志输出到标准输出(控制台),设置了慢 SQL 的阈值为 200 毫秒,只记录警告及以上级别的日志,并启用彩色输出。

日志的 writer 构造函数 抽离出来,封装在 initialize/internal/logger.go 中:

package internal
import (
   "ewa_admin_server/global"
   "fmt"
   "gorm.io/gorm/logger"
)
type writer struct {
   logger.Writer
}
// NewWriter writer 构造函数
func NewWriter(w logger.Writer) *writer {
   return &writer{Writer: w}
}
// Printf 格式化打印日志
func (w *writer) Printf(message string, data ...interface{}) {
   var logZap bool
   switch global.EWA_CONFIG.App.DbType {
   case "mysql":
      logZap = global.EWA_CONFIG.MySQL.LogZap
   }
   if logZap {
      global.EWA_LOG.Info(fmt.Sprintf(message+"\n", data...))
   } else {
      w.Writer.Printf(message, data...)
   }
}

2.4 初始化数据库

准备工作做好之后,我们就可以连接数据库了,在 initialize 中新建一个 gorm.go 来专门处理数据库的连接

package initialize
import (
   "ewa_admin_server/global"
   "gorm.io/gorm"
)
// Gorm 初始化数据库并产生数据库全局变量
func Gorm() *gorm.DB {
   switch global.EWA_CONFIG.App.DbType {
   case "mysql":
      return GormMysql()
   default:
      return GormMysql()
   }
}

main.go 中:

package main
import (
   "ewa_admin_server/core"
   "ewa_admin_server/global"
   "ewa_admin_server/initialize"
   "go.uber.org/zap"
   "github.com/gin-gonic/gin"
)
const AppMode = "debug" // 运行环境,主要有三种:debug、test、release
func main() {
   gin.SetMode(AppMode)
   // TODO:1.配置初始化
   global.EWA_VIPER = core.InitializeViper()
   // TODO:2.日志
   global.EWA_LOG = core.InitializeZap()
   zap.ReplaceGlobals(global.EWA_LOG)
   global.EWA_LOG.Info("server run success on ", zap.String("zap_log", "zap_log"))
   //  TODO:3.数据库连接
   global.EWA_DB = initialize.Gorm()
   // TODO:4.其他初始化
   // TODO:5.启动服务
   core.RunServer()
}

是不是就可以连接数据库了?试试
image.png
为什么呢?因为我们还没有建立数据库啊!光有插头,没插座啊~

2.5 新建数据库

我这里使用的数据库图形化管理工具是 Navicat,它支持 MySQLPostgreSQL,你也可以使用其他的工具,最好是支持这两种,因为项目会用到,然后就可以新建一个数据库了:

image.png
image.png重启项目,如果你看到下面的控制台信息,恭喜你,成功了!
image.png

3、Go 连接 PostgreSQL

PostgreSQL 是一种强大的、开源的关系型数据库管理系统(RDBMS),PostgreSQL 是一个功能强大、高度可靠且安全的数据库平台,因此被广泛用于企业级应用程序和数据管理领域。它具有以下优点:

  1. 可扩展性:PostgreSQL 可以在不停机的情况下进行水平扩展和垂直扩展,通过分片和集群等方式使其支持大型企业级应用程序。
  2. 高度可靠性:PostgreSQL 被认为是一个极其可靠的数据库平台,能够提供容错、恢复能力。因此,它通常被用于需要高度稳定性的企业级系统。
  3. 具有完整的事务性支持:PostgreSQL 支持 ACID(原子性、一致性、隔离性、持久性)事务处理,并保证数据的一致性和正确性。
  4. 开源免费:作为开源软件,PostgreSQL 可以免费使用,没有任何版权或商业限制,同时也有活跃的社区支持。
  5. 丰富的扩展:PostgreSQL 有成千上万的扩展和插件,给予应用程序更多的选择和功能支持,包括数据类型、索引类型、查询函数和存储过程等等。
  6. 安全性高:PostgreSQL 提供了各种安全选项,例如 SSL支持加密连接ACL支持等等。同时,由于其通用性,它还在多个不同的平台上运行,包括各种 Linux发行版WindowsMacOS 等。

按照Gorm官方文档的demo,我们还需要安装一个 driver

go get gorm.io/driver/postgres

同样,我们需要安装 PostgreSQL 数据库:

3.1 定义 PostgreSQL 配置

# ...
pgsql: # PostgreSQL 配置
  host: "localhost" # 服务器地址
  port: "5432" # 端口
  config: "sslmode=disable TimeZone=Asia/Shanghai" # 其他配置
  db_name: east_white_admin_server # 数据库名称
  username: "ian_kevin" # 数据库用户名
  password: "123456" # 数据库密码
  prefix: "t_" # 全局表前缀,单独定义 TableName 则不生效
  singular: false # 是否开启全局禁用复数,true表示不开启
  engine: "" # 引擎,默认InnoDB
  max_idle_conns: 10 # 最大空闲连接数
  max_open_conns: 100 # 最大连接数
  log_mode: error # 日志级别
  log_zap: false # 是否通过zap写日志文件

3.2 结构体和方法

接下来,需要用结构体对配置进行解析,然后将其挂载到全局变量上。在 config 下新建 gorm_pgsql.go,定义如下的结构体:

package config
type PGSQL struct {
   Host         string `mapstructure:"host" json:"host" yaml:"host"`                               // 服务器地址:端口
   Port         string `mapstructure:"port" json:"port" yaml:"port"`                               //:端口
   Config       string `mapstructure:"config" json:"config" yaml:"config"`                         // 高级配置
   Dbname       string `mapstructure:"db_name" json:"db_name" yaml:"db_name"`                      // 数据库名
   Username     string `mapstructure:"username" json:"username" yaml:"username"`                   // 数据库用户名
   Password     string `mapstructure:"password" json:"password" yaml:"password"`                   // 数据库密码
   Prefix       string `mapstructure:"prefix" json:"prefix" yaml:"prefix"`                         // 全局表前缀,单独定义TableName则不生效
   Singular     bool   `mapstructure:"singular" json:"singular" yaml:"singular"`                   // 是否开启全局禁用复数,true表示开启
   Engine       string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"`        // 数据库引擎,默认InnoDB
   MaxIdleConns int    `mapstructure:"max_idle_conns" json:"max_idle_conns" yaml:"max_idle_conns"` // 空闲中的最大连接数
   MaxOpenConns int    `mapstructure:"max_open_conns" json:"max_open_conns" yaml:"max_open_conns"` // 打开到数据库的最大连接数
   LogMode      string `mapstructure:"log_mode" json:"log_mode" yaml:"log_mode"`                   // 是否开启Gorm全局日志
   LogZap       bool   `mapstructure:"log_zap" json:"log_zap" yaml:"log_zap"`                      // 是否通过zap写入日志文件
}
// Dsn 基于配置文件获取 dsn
func (p *PGSQL) Dsn() string {
   return "host=" + p.Host + " user=" + p.Username + " password=" + p.Password + " dbname=" + p.Dbname + " port=" + p.Port + " " + p.Config
}
// LinkDsn 根据 dbname 生成 dsn
func (p *PGSQL) LinkDsn(dbname string) string {
   return "host=" + p.Host + " user=" + p.Username + " password=" + p.Password + " dbname=" + dbname + " port=" + p.Port + " " + p.Config
}
func (m *PGSQL) GetLogMode() string {
   return m.LogMode
}

然后也需要和 MySQL 一样,将其统一配置在 config.go 中:

package config
type Configuration struct {
   App   App   `mapstructure:"app" json:"app" yaml:"app"`
   Zap   Zap   `mapstructure:"zap" json:"zap" yaml:"zap"`
   MySQL MySQL `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
   Pgsql PGSQL `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"`
}

3.3 封装数据库连接方法

我们在根目录下新建一个 initialize 作为一些需要在程序启动时初始化的操作集合。在这个文件中新建 gorm_pgsql.go 文件:

package initialize
import (
   "ewa_admin_server/global"
   "ewa_admin_server/initialize/internal"
   "fmt"
   "gorm.io/driver/postgres"
   "gorm.io/gorm"
)
// GormPgSql 初始化 Postgresql 数据库
func GormPgSql() *gorm.DB {
   p := global.EWA_CONFIG.Pgsql
   if p.Dbname == "" {
      return nil
   }
   pgsqlConfig := postgres.Config{
      DSN:                  p.Dsn(), // DSN data source name
      PreferSimpleProtocol: false,
   }
   db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config(p.Prefix, p.Singular))
   if err != nil {
      return nil
   } else {
      sqlDB, _ := db.DB()
      sqlDB.SetMaxIdleConns(p.MaxIdleConns)
      sqlDB.SetMaxOpenConns(p.MaxOpenConns)
      fmt.Println("====3-gorm====: gorm link PostgreSQL success")
      return db
   }
}

然后在 initialize/gorm.go 中增加使用 PostgreSQL 时的方法:

package initialize
import (
   "ewa_admin_server/global"
   "gorm.io/gorm"
)
// Gorm 初始化数据库并产生数据库全局变量
func Gorm() *gorm.DB {
   switch global.EWA_CONFIG.App.DbType {
   case "mysql":
      return GormMysql()
   case "pgsql":
      return GormPgSql()
   default:
      return GormMysql()
   }
}

如果你更习惯使用其他的数据库,也可以通过类似的思路进行配置。

3.4 PostgreSQL 图形化工具

我这里使用的是 pgAdmin,安装流程就不赘述了。安装完成之后,在 shell 工具中,通过如下的指令建立对应的数据库:

# 查看 PostgreSQL 服务是否启动
brew services list
# 指定数据库连接 PostgreSQL 
psql -d postgres
# 创建用户 
CREATE USER ian_kevin WITH PASSWORD '123456'; 
# 创建数据库 
CREATE DATABASE east_white_admin_server; 

然后再 pgAdmin 中连接到对应的服务,就可以看到里面有了我们创建的数据库了:
image.png

3.5 测试

config.yaml 中的 db_type 改成 pgsql,然后重启项目,如果你看到下面的信息,就说明连接成功了:

image.pngend~ 这就是链接数据库的全部内容了,下一篇我们将继续完成一些基础的配置,然后开始一些简单的 CRUD

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
10天前
|
存储 SQL API
探索后端开发:构建高效API与数据库交互
【10月更文挑战第36天】在数字化时代,后端开发是连接用户界面和数据存储的桥梁。本文深入探讨如何设计高效的API以及如何实现API与数据库之间的无缝交互,确保数据的一致性和高性能。我们将从基础概念出发,逐步深入到实战技巧,为读者提供一个清晰的后端开发路线图。
|
10天前
|
Go UED
Go Web服务中如何优雅平滑重启?
在生产环境中,服务升级时如何确保不中断当前请求并应用新代码是一个挑战。本文介绍了如何使用 Go 语言的 `endless` 包实现服务的优雅重启,确保在不停止服务的情况下完成无缝升级。通过示例代码和测试步骤,详细展示了 `endless` 包的工作原理和实际应用。
27 3
|
11天前
|
存储 SQL 数据库
深入浅出后端开发之数据库优化实战
【10月更文挑战第35天】在软件开发的世界里,数据库性能直接关系到应用的响应速度和用户体验。本文将带你了解如何通过合理的索引设计、查询优化以及恰当的数据存储策略来提升数据库性能。我们将一起探索这些技巧背后的原理,并通过实际案例感受优化带来的显著效果。
29 4
|
12天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
28 4
|
13天前
|
SQL 关系型数据库 MySQL
go语言中安装数据库驱动
【11月更文挑战第1天】
35 5
|
11天前
|
JSON Go UED
Go Web服务中如何优雅关机?
在构建 Web 服务时,优雅关机是一个关键的技术点,它确保服务关闭时所有正在处理的请求都能顺利完成。本文通过一个简单的 Go 语言示例,展示了如何使用 Gin 框架实现优雅关机。通过捕获系统信号和使用 `http.Server` 的 `Shutdown` 方法,我们可以在服务关闭前等待所有请求处理完毕,从而提升用户体验,避免数据丢失或不一致。
15 1
|
14天前
|
SQL 关系型数据库 MySQL
go语言中数据库操作
【10月更文挑战第22天】
28 4
|
14天前
|
缓存 前端开发 中间件
go语言中Web框架
【10月更文挑战第22天】
26 4
|
13天前
|
关系型数据库 MySQL 数据库连接
go语言中打开数据库连接
【11月更文挑战第1天】
27 2
|
21天前
|
关系型数据库 MySQL Linux
Linux系统如何设置自启动服务在MySQL数据库启动后执行?
【10月更文挑战第25天】Linux系统如何设置自启动服务在MySQL数据库启动后执行?
66 3