前言

作为数据存储的数据库,近年来发展飞快,在早期的程序自我存储到后面的独立出中间件服务,再到集群,不可谓不快了。早期的sql数据库一枝独秀,到后面的Nosql,还有azure安全,五花八门,教人学不过来阿。

一、mysql数据库的golang操作

针对数据库操作,往往需要安装实体数据库和对应的数据库驱动,前者要实际安装配置,可参考菜鸟官网的mysql安装,后者则是下载安装第三方库即可。

jam@jam:~$ mysql -h127.0.0.1 -ujam -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.0.33 MySQL Community Server - GPL Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
| somedb |
+--------------------+
3 rows in set (0.00 sec) mysql> use somedb;
Database changed
mysql> show tables;
Empty set (0.01 sec) mysql>

这边已经准备好了本地数据库实体,也添加了somedb数据库和对应的jam用户,供golang的调用操作练习。

1.1 database/sql使用

用golang的database/sql接口来进行sql硬编码,后续得到的结果自己硬解码,不过golang需要下载数据库驱动go get github.com/go-sql-driver/mysql,下载好了以后,就是编写sql语句和定流程的事了。

大致程序流程就是连接数据库,调用exec类api来执行sql语句,在python用pymysql等第三方库操作的时候,还需要在插入和更新表数据的时候来个commit,golang倒是不用,就直接Exec,具体如下:

const (
USERNAME = "jam"
PWD = "abaaba"
NETWORK = "tcp"
SERVER = "127.0.0.1"
PORT = 3306
DATABASE = "somedb"
) type Student struct {
Id int
Name string
} func main() {
conn := fmt.Sprintf("%s:%s@%s(%s:%d)/%s", USERNAME, PWD, NETWORK, SERVER, PORT, DATABASE)
db, err := sql.Open("mysql", conn)
if err != nil {
fmt.Println("mysql数据库连接失败:", err)
return
}
//设置连接存活时间
db.SetConnMaxLifetime(60 * time.Second)
//设置最大连接数
db.SetMaxOpenConns(10) createTable(db)
insert(db, 1, "小昏")
insert(db, 2, "meiyi")
insert(db, 3, "明也")
query_single(db, 1)
//更新数据
update(db, 1, "baba")
all_query(db)
drop(db)
}

程序主体便是这样,几个执行sql语句根据语义包装成函数分开调用,另外因为用的是IDEA的goland,所以踩了不少的坑,关于数据库在ide中的配置出现了不少warning,有点烦。针对sql中的insert,update,delete操作还是使用db.Exec来对应调用:

// 插入,直接Exec一个sql也行
func insert(db *sql.DB, id int, name string) {
sql_state, err := db.Prepare("insert into students values (?, ?)")
res, err := sql_state.Exec(id, name)
if err != nil {
fmt.Println("插入失败:", err)
return
}
lastInsertID, _ := res.LastInsertId()
fmt.Println("插入id:", lastInsertID)
rowsaffected, _ := res.RowsAffected()
fmt.Println("affected rows:", rowsaffected)
} // 修改
func update(db *sql.DB, id int, name string) {
if res, err := db.Exec("update students set name=? where id=?", name, id); err != nil {
fmt.Println("更新表失败:", err)
} else {
fmt.Println("更新结果:", res)
}
} // 删除指定id对应的行
func delete(db *sql.DB, id int) {
if res, err := db.Exec("delete from students where id=?", id); err != nil {
fmt.Println("删除失败:", err)
return
} else {
fmt.Println("删除结果:", res)
}
}

然后针对查询的就用db.Query一类接口:

// 查询一行
func query_single(db *sql.DB, id int) {
student := new(Student)
row := db.QueryRow("select * from students where id=?", id)
if err := row.Scan(&student.Id, &student.Name); err != nil {
fmt.Println("scan失败:", err)
return
}
fmt.Println("第一行数据:", *student)
} func all_query(db *sql.DB) {
students := new(Student)
rows, err := db.Query("select * from students") defer func() {
if rows != nil {
rows.Close()
}
}()
if err != nil {
fmt.Println("查询失败:", err)
return
}
for rows.Next() {
err = rows.Scan(&students.Id, &students.Name)
if err != nil {
fmt.Println("scan失败:", err)
return
}
fmt.Println("scan successed:", *students)
}
}

另外还有创建表和删除表的操作,也还是用Exec,因为没返回嘛:

func createTable(db *sql.DB) {
sql_s := `create table if not exists students (
id int unsigned not null auto_increment primary key ,
name varchar(10) not null unique
)engine=InnoDB default charset=utf8;`
if _, err := db.Exec(sql_s); err != nil {
fmt.Println("创表失败:", err)
return
}
} func drop(db *sql.DB) {
if _, err := db.Exec("drop table students"); err != nil {
fmt.Println("删表失败:", err)
}
}

针对包引入部分,代码中是这样:

package main

import (
"database/sql"
"fmt"
"time" _ "github.com/go-sql-driver/mysql"
)

但实际中关于golang项目还有不少go modules的设置,这里只是实际记录,不做项目前准备的记录。走完一圈,可以发现database/sql提供的也就只是一个连接和对应的exec执行sql语句的接口,对于专门的coder来说,需要另外兼顾sql中的语法,未免有点麻烦,所以有了ORM技术--各玩各的。

二、gorm操作mysql

ORM技术,就是让高级语言的代码编辑专注于该语言的语法,而不用去另外理会sql的语义,具体实现就是,用类似c中的struct,cpp中的class,golang中的struct这类存储结构性信息来对接数据库中的关系型数据,中间的转换问题由专门的库负责,python中的是sqlalchemy,golang中目前接触的就是gorm了。

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

在项目中go get一下下载gorm库和对应mysql驱动即可,不同数据库对应不同驱动。

连接一下,然后进行设置:

const (
Host = "127.0.0.1"
User = "jam"
Pwd = "abaaba"
Port = 3306
Net = "tcp"
Database = "somedb"
) //空配置
func main() {
dst_uri := fmt.Sprintf("%s:%s@%s(%s:%d)/%s", User, Pwd, Net, Host, Port, Database)
//简单无配置
//db, err := gorm.Open(mysql.Open(dst_uri), &gorm.Config{}) //配置mysql驱动
//db, err := gorm.Open(mysql.New(mysql.Config{
// DSN: dst_uri,
// DefaultStringSize: 256, //string类型字符串默认长度
// DisableDatetimePrecision: true, //禁用datetime精度
// DontSupportRenameIndex: true, //重命名索引时使用删除并新建的方式
// DontSupportRenameColumn: true, //用change重命名列
// SkipInitializeWithVersion: false, //是否根据当前mysql版本自适应配置
//}), &gorm.Config{}) //gorm
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: dst_uri,
}), &gorm.Config{
SkipDefaultTransaction: false,
NamingStrategy: schema.NamingStrategy{
SingularTable: true, // 表名复数形式
TablePrefix: "t_", //表名前缀
},
DisableForeignKeyConstraintWhenMigrating: true, //设置逻辑外键,体现在代码上
}) //获取通用数据库对象sql.DB
sql_db, err := db.DB()
//设置连接池中空闲连接的最大数量
sql_db.SetMaxIdleConns(10)
//设置打开数据库连接的最大数
sql_db.SetConnMaxLifetime(time.Hour)
fmt.Println(sql_db, err)
}

建表

//通过自动迁移来建表,说白了就是提供好golang中的数据结构,然后调用接口给gorm就行,转换的问题交给gorm了
func auto_migrate(db *gorm.DB) {
type book struct {
id int
name string
price float32
} err := db.AutoMigrate(&book{})
if err != nil {
fmt.Println(err)
}
} //手动迁移的方式建表
func migrate(db *gorm.DB) {
type view struct {
Id int
Name string
} m := db.Migrator()
if !m.HasTable(&view{}) {
m.CreateTable(&view{})
} else {
fmt.Println("已存在同名表")
}
}

测试了一下,自动迁移的方式会针对同名表的创建有个判断,判断同名表是否存在的步骤,其实自动迁移的实现就是内部调用了Migrator接口的一个方法:

func (db *DB) AutoMigrate(dst ...interface{}) error {
return db.Migrator().AutoMigrate(dst...)
}
// Migrator migrator interface
type Migrator interface {
//下一小节
}

记,作为gorm的golang结构体的构造,内部成员名要大写开头

后续操作,也是基于Migrator这个接口的基础,因为它有许多方法:

        ...
//重命名
m := db.Migrator()
type view2 struct {
Id int
Name string
}
m.RenameTable(&view{}, &view2{})
fmt.Println("是否存在view2:", m.HasTable(&view2{}))
m.RenameTable(&view2{}, "view3") type view3 struct {
Id int
Name string
}
//删表
m.DropTable(&view3{})
fmt.Println("是否存在表view3:", m.HasTable(&view3{}))

插入,更新,删除,查询操作

        ...
type view struct {
Id int
Name string
}
type book struct {
Id int
Name string
Price float32
} //插入
views := []view{{1, "wind"}, {2, "rain"}}
db.Create(&views)
//查询, 获取第一条记录,并且更新
v := new(View)
db.First(&v)
fmt.Println(v.Id, v.Name)
//更新
v.Id = 4
v.Name = "river"
db.Save(&v)
//再查找然后删除表记录
db.Where("id=?", 3).Delete(&View{})

差不多就这样,更多api可以查看官方中文文档

另外,除了上面的mysql以外,还可以连接本地的sqlite数据库,下载对应驱动就行,也验证了上面的一个说法。

sql数据库连接的更多相关文章

  1. SQL数据库连接到服务器出错——无法连接到XXX

    问题:Windows或者SQL Server身份验证下,出现连接到服务器出错 解决方式: 1.检查实例名称是否正确,如下 根据自己电脑的实际名称修改修改如下: 1)Microsoft SQL Serv ...

  2. SQL数据库连接池与C#关键字return

    SQL数据库连接池: 先前做的一个Sharepoint项目,在上线后的不久,最近一直出现间歇性访问缓慢问题Sharepoint特性问题,并分析了其数据库服务器,发现所耗内存已经达到了97%. 所以断定 ...

  3. Java之MS SQL数据库连接

    一  1.首先,到微软官方下载jdbc驱动包 Microsoft JDBC Driver 4.0 for SQL Server 2.运行sqljdbc_4.0.2206.100_chs.exe,把文件 ...

  4. web第一节课 sql 数据库连接 查询

    1.数据库连接语句 <connectionStrings> <add name="yhotel" connectionString="Database= ...

  5. C# KTV 系统 SQL数据库连接 C# 应用窗体

    ---恢复内容开始--- 五道口 北大青鸟校区 KTV项目 指导老师: 袁玉明  SQL数据库关系图 第一步: private void DoubleClicklvContry() { ]!=null ...

  6. Go组件学习——database/sql数据库连接池你用对了吗

    1.案例 case1: maxOpenConns > 1 func fewConns() { db, _ := db.Open("mysql", "root:roo ...

  7. 远程sql数据库连接不上,provider: 命名管道提供程序, error: 40 - 无法打开到 SQL Server 的连接 错误解决

    错误信息: “ 标题: 连接到服务器------------------------------ 无法连接到 192.168.1.20. ------------------------------其 ...

  8. asp.net 可视化操作(二)——Sql数据库连接及简单查询功能的实现

    目录 连接数据库 利用repeater控件实现数据显示 查询功能 页面CSS美化 数据插入.更新-- 连接数据库 添加test.aspx 添加控件SqlDataSource,选择配置数据源 选择新建连 ...

  9. dedecms SQL数据库连接信息注解(借鉴)

    <?php $cfg_dbhost = 'localhost'; //数据库地址,这里的localhost指的是本机$cfg_dbname = 'hunuo'; //数据库名$cfg_dbuse ...

  10. SQL数据库连接语句

    一般的远程访问的写成这样: Data Source=IP ;Initial Catalog=数据库名 ;UserID= 用户名 ;Password=密码 本地访问的写成这样: Data Source= ...

随机推荐

  1. w3cschool-Flink 入门

    Flink 入门   Apache Flink是一个框架和分布式处理引擎,用于在无界和有界数据流上进行有状态的计算.Flink被设计为在所有常见的集群环境中运行,以内存中的速度和任何规模执行计算. A ...

  2. 在linux系统通过OpenSSL工具自签https证书

    工具介绍 OpenSSL是SSL/TLS协议的实现工具 key是私钥文件,用于对发送给客户端的数据加密,以及对从客户端接收的数据进行解密. csr是证书签名请求文件,用于提交给证书颁发机构(CA)对证 ...

  3. selenium学习-常用方法

    id_#当前元素的ID  tag_name#获取元素标签名的属性  text#获取该元素的文本.  click()#单击(点击)元素  submit()#提交表单  clear()#清除一个文本输入元 ...

  4. 使用kNN算法改进约会网站配对效果(尺度归一化问题)

    简单匹配:

  5. IOC操作Bean 管理(基于 xml 方式)

    1.什么是 Bean 管理(0)Bean 管理指的是两个操作(1)Spring 创建对象(2)Spirng 注入属性 2.Bean 管理操作有两种方式(1)基于 xml 配置文件方式实现(2)基于注解 ...

  6. Nodejs 实现一个CRC16校验

    近日在开发一个数据平台,据说nodejs比较适合DIRT类型的程序,所以也搞了一把,虽然接收.转发及其报文解析等功能顺利的实现了,但是由于某些报文涉及到应答,故而需要CRC校验,也算是一个小坑吧,故而 ...

  7. 使用Chainlit快速构建一个对话式人工智能应用体验DeepSeek-R1

    Chainlit是一个开源的 Python 包,用于构建可用于生产的对话式人工智能. DeepSeek-R1 是一款强化学习(RL)驱动的推理模型,解决了模型中的重复性和可读性问题.在 RL 之前,D ...

  8. Linux驱动---字符设备

    目录 一.基础简介 1.1.Linux设备驱动分类 1.2.字符设备驱动概念 二.驱动基本组成 2.1.驱动模块的加载和卸载 2.2.添加LICENNSE以及其他信息 三.字符设备驱动开发步骤 3.1 ...

  9. Springboot 3.x 集成Knife4j [踩坑日记]

    之前项目用的是SpringBoot2.x 新项目用了SpringBoot3.x版本,引入Knife4j 报错java.lang.TypeNotPresentException: Type javax. ...

  10. stay:将代码翻译为Gif动图,妈妈再也不用担心我调试找不到bug了

    本文首发于微信公众号:呼哧好大枫.原作者与本文作者是同一人. 平常在做算法题或者是 debug 的时候很需要一款能够实时地将代码执行逻辑和数据以图形化的形式渲染出来的工具.之前尝试了几款(visual ...