sql数据库连接
前言
作为数据存储的数据库,近年来发展飞快,在早期的程序自我存储到后面的独立出中间件服务,再到集群,不可谓不快了。早期的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数据库连接的更多相关文章
- SQL数据库连接到服务器出错——无法连接到XXX
问题:Windows或者SQL Server身份验证下,出现连接到服务器出错 解决方式: 1.检查实例名称是否正确,如下 根据自己电脑的实际名称修改修改如下: 1)Microsoft SQL Serv ...
- SQL数据库连接池与C#关键字return
SQL数据库连接池: 先前做的一个Sharepoint项目,在上线后的不久,最近一直出现间歇性访问缓慢问题Sharepoint特性问题,并分析了其数据库服务器,发现所耗内存已经达到了97%. 所以断定 ...
- Java之MS SQL数据库连接
一 1.首先,到微软官方下载jdbc驱动包 Microsoft JDBC Driver 4.0 for SQL Server 2.运行sqljdbc_4.0.2206.100_chs.exe,把文件 ...
- web第一节课 sql 数据库连接 查询
1.数据库连接语句 <connectionStrings> <add name="yhotel" connectionString="Database= ...
- C# KTV 系统 SQL数据库连接 C# 应用窗体
---恢复内容开始--- 五道口 北大青鸟校区 KTV项目 指导老师: 袁玉明 SQL数据库关系图 第一步: private void DoubleClicklvContry() { ]!=null ...
- Go组件学习——database/sql数据库连接池你用对了吗
1.案例 case1: maxOpenConns > 1 func fewConns() { db, _ := db.Open("mysql", "root:roo ...
- 远程sql数据库连接不上,provider: 命名管道提供程序, error: 40 - 无法打开到 SQL Server 的连接 错误解决
错误信息: “ 标题: 连接到服务器------------------------------ 无法连接到 192.168.1.20. ------------------------------其 ...
- asp.net 可视化操作(二)——Sql数据库连接及简单查询功能的实现
目录 连接数据库 利用repeater控件实现数据显示 查询功能 页面CSS美化 数据插入.更新-- 连接数据库 添加test.aspx 添加控件SqlDataSource,选择配置数据源 选择新建连 ...
- dedecms SQL数据库连接信息注解(借鉴)
<?php $cfg_dbhost = 'localhost'; //数据库地址,这里的localhost指的是本机$cfg_dbname = 'hunuo'; //数据库名$cfg_dbuse ...
- SQL数据库连接语句
一般的远程访问的写成这样: Data Source=IP ;Initial Catalog=数据库名 ;UserID= 用户名 ;Password=密码 本地访问的写成这样: Data Source= ...
随机推荐
- UWP 系统通知测试
code: using System; using System.Collections.Generic; using System.IO; using System.Linq; using Syst ...
- 一. 初始 Redis(快速入门-00)
一. 初始 Redis(快速入门-00) @ 目录 一. 初始 Redis(快速入门-00) Redis 概述: 关系型数据库(如 MySQL ) 问题 NoSQL 数据库(非关系性数据库) 最后: ...
- Winform-耗时操作导致界面渲染滞后
原因: 某些耗时操作阻塞了主线程. 理解上述原因,需先搞清楚Winform线程机制.主要有以下2点特性:1.单线程模型:2.依赖消息循环. 1.单线程模型 Winform 默认是单线程.通常,所有的U ...
- Python 潮流周刊#87:媲美 OpenAI-o1 的开源模型(摘要)
本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...
- 一个登录功能也能玩出这么多花样?sa-token带你轻松搞定多地登录、单地登录、同端互斥登录
需求场景 说起登录,你可能会不屑一顾,还有比这更简单的功能吗? 获取一下用户提交参数 username + password 和数据库中一比对,有记录返回[登录成功],无记录返回[用户名或密码错误] ...
- linux mint安装kafka,及flume与kafka整合
需要软件 jdk1.8(jdk-8u131-linux-x64.rpm) zookeeper (zookeeper-3.4.10.tar.gz) kafka 2.11-2.0.0 flume1.8.0 ...
- Linux下Docker及Nvidia Container ToolKit安装教程
作者:SkyXZ CSDN:SkyXZ--CSDN博客 博客园:SkyXZ - 博客园 我们接下来在Ubuntu中安装Docker(安装详见:Get Docker | Docker Docs)及NVI ...
- JAVA运算符及实例
JAVA语言支持以下运算符 优先级() 算数运算符:+,-,*,/,%,++,-- 实例1: package operator; public class Demo01 { public ...
- 你还不会使用Pycham Remote development 打开远程主机工作目录吗?这篇文章帮你解决!
前言 必备: 本地开发机与远程主机都要安装Pycharm专业版!!! 废话不多说直接开始!! 1.打开pycharm 2.依次点击File.Remote Development 3.依次点击SSH.N ...
- linux的使用(2)
1,覆盖 > cat 文件名a>文件名b:将文档a覆盖文档b 2,追加 >> cat 文档名a>>文档名b:将文档a追加到文档b后 追加错误 上图所示:尽量使用字母 ...