【Go基础】数据库编程

news2024/10/7 14:23:02

文章目录

    • 1. SQL语法简介
    • 2. MySQL最佳实践
    • 3. Go SQL驱动接口解读
    • 4. 数据库增删改查
    • 5. stmt
    • 6. SQLBuilder
      • 6.1 Go-SQLBuilder
      • 6.2 Gendry
      • 6.3 自行实现SQLBuilder
    • 7. GORM
    • 8. Go操作MongoDB

1. SQL语法简介

SQL(Structured Query Language)是一套语法标准,不区分大小写
MySQL、sql-server和Oracle都是关系型数据库,在一些高级语法上跟标准SQL略有出入
Linux用户安装MySQL服务端

yum install mysql-server

安装MySQL客户端

yum install mysql

启动MySQL服务端

service mysqld start

以管理员登录

mysql -h localhost -P 3306 -u root -p'123456'
  • -h:mysql server host,不写时默认是localhost
  • -P:mysql server port,不写时默认是3306
  • -u:user name,-u后可以加空格也可以不加
  • -p:password,密码中可能包含空格,所以要加引号,高版本的mysql不允许在命令行中直接输入密码,此时只输入-p后面不要写密码即可创建账号
create user 'tester' identified by '123456'

创建database

create database test

把特定database的操作权限授予一个普通用户

grant all on test.* to tester;

以普通用户登录

mysql -utester -p'123456'

使用database

use test

创建表

create table if not exists student(
    id int not null auto_increment comment '主键自增id',
    name char(10) not null comment '姓名',
    province char(6) not null comment '省',
    city char(10) not null comment '城市',
    addr varchar(100) default '' comment '地址',
    score float not null default 0 comment '考试成绩',
    enrollment date not null comment '入学时间',
    primary key (id),  unique key idx_name (name),  
    key idx_location (province,city)
)default charset=utf8 comment '学员基本信息';

新增记录,必须给not null且无default值的列赋值

insert into student (name,province,city,enrollment) values
    ('张三','北京','北京','2021-03-05'),
    ('李四','河南','郑州','2021-04-25'),
    ('小丽','四川','成都','2021-03-10');

查询

select id,name from student where id>0;

select province,avg(score) as avg_score from student 
    where score>0 
    group by province having avg_score>50 
    order by avg_score desc;

修改

update student set score=score+10,addr='海淀' where province='北京';

update student set
    score=case province
        when '北京' then score+10     
        when '四川' then score+5 
        else score+7
    end,
    addr=case province
        when '北京' then '东城区'        
        when '四川' then '幸福里'        
        else '朝阳区'    
    end
where id>0;

删除

delete from student where city= '郑州';
delete from student;	--删除表里的所有行
drop table student;	    --删除表

2. MySQL最佳实践

  • 写sql时一律使用小写
  • 建表时先判断表是否已存在if not exists
  • 所有的列和表都加comment
  • 字符串长度比较短时尽量使用char,定长有利于内存对齐,读写性能更好,而varchar字段频繁修改时容易产生内存碎片
  • 满足需求的前提下尽量使用短的数据类型,如tinyint vs int, float vs double, date vs datetime

null

  • default null有别于default ''和default 0
  • is null, is not null有别于!= ‘’, !=0
  • 尽量设为not null
    • 有些DB索引列不允许包含null
    • 对含有null的列进行统计,结果可能不符合预期
    • null值有时候会严重拖慢系统性能

索引

在这里插入图片描述

  • B即Balance,对于m叉树每个节点上最多有m个数据,最少有m/2个数据(根节点除外)

  • 叶节点上存储了所有数据,把叶节点链接起来可以顺序遍历所有数据

  • 每个节点设计成内存页的整倍数。MySQL的m=1200,树的前两层放在内存中

  • MySQL索引默认使用B+树

  • 主键默认会加索引。按主键构建的B+树里包含所有列的数据,而普通索引的B+树里只存储了主键,还需要再查一次主键对应的B+树(回表)

  • 联合索引的前缀同样具有索引的效果

  • sql语句前加explain可以查看索引使用情况

  • 如果MySQL没有选择最优的索引方案,可以在where前force index(index_name)

规避慢查询

  • 大部分的慢查询都是因为没有正确地使用索引。查看一条SQL语句使用索引的情况只需要在SQL前加个explain
  • 一次select不要超过1000行
  • 分页查询limit m,n会检索前m+n行,只是返回后n行,通常用id>x来代替这种分页方式(stmt一节会展示遍历整个table的正确姿势)
  • 批量操作时最好一条sql语句搞定;其次打包成一个事务,一次性提交(高并发情况下减少对共享资源的争用)
  • 不要使用连表操作,join逻辑在业务代码里完成

3. Go SQL驱动接口解读

Go官方没有提供数据库驱动,而是为开发数据库驱动定义了一些标准接口(即database/sql),开发者可以根据定义的接口来开发相应的数据库驱动
Go中支持MySQL的驱动比较多,如:

  • github.com/go-sql-driver/mysql 支持 database/sql
  • github.com/ziutek/mymysql 支持 database/sql,也支持自定义的接口
  • github.com/Philio/GoMySQL 不支持 database/sql,自定义接口

Driver

type Driver interface { 
    Open(name string) (Conn, error) 
}
var d = Driver{proto: "tcp", raddr: "127.0.0.1:3306"}
sql.Register("mysql", &d) // 注册数据库驱动

Conn

type Conn interface {
    Prepare(query string) (Stmt, error) // 把一个查询query传给Prepare,返回Stmt(statement)
    Close() error // 关闭数据库连接
    Begin() (Tx, error) // 返回一个事务Tx(transaction)
}

Stmt

type Stmt interface {
    Close() error // 关闭当前的链接状态
    NumInput() int // 返回当前预留参数的个数
    Exec(args []Value) (Result, error) // 执行Prepare准备好的 sql,传入参数执行 update/insert 等操作,返回 Result 数据
    Query(args []Value) (Rows, error) // 执行Prepare准备好的 sql,传入需要的参数执行 select 操作,返回 Rows 结果集
}

Tx

type Tx interface {
    Commit() error // 提交事务
    Rollback() error // 回滚事务
}

Result

type Result interface {
    LastInsertId() (int64, error) // 返回由数据库执行插入操作得到的自增ID号,如果使用单个INSERT将多行插入到表中,则LastInsertId是第一条数据使用的id
    RowsAffected() (int64, error) // 返回操作影响的数据条目数
}

RowsAffected
RowsAffected是int64的别名,它实现了Result接口

type RowsAffected int64
func (RowsAffected) LastInsertId() (int64, error)
func (v RowsAffected) RowsAffected() (int64, error)

Rows

type Rows interface {
    Columns() []string // 查询所需要的表字段
    Close() error // 关闭迭代器
    Next(dest []Value) error // 返回下一条数据,把数据赋值给dest,dest里面的元素必须是 driver.Value的值,如果最后没数据了,Next 函数返回 io.EOF
}

Value

type Value interface{}

Value 要么是 nil,要么是下面的任意一种

  • int64
  • float64
  • bool
  • []byte
  • string
  • time.Time

ValueConverter

type ValueConverter interface {
    //把数据库里的数据类型转换成Value允许的数据类型
    ConvertValue(v interface{}) (Value, error)
}

4. 数据库增删改查

下载第三方库

go get github.com/go-sql-driver/mysql

连接数据库

db, err := sql.Open("mysql", "root:@tcp(localhost:3306)/test?charset=utf8")

DSN(data source name)格式:

[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]  

例如:user:password@tcp(localhost:5555)/dbname?charset=utf8mb4&parseTime=True
如果是本地MySQl,且采用默认的3306端口,可简写为:user:password@/dbname
连接参数要支持完整的UTF-8编码,您需要将charset=utf8更改为charset=utf8mb4;想要正确的处理time.Time ,您需要带上parseTime参数

增删改

func (*sql.DB).Exec(sql string) (sql.Result, error)

func (*sql.DB).Query(sql string) (*sql.Rows, error)

crud.go


import (
	"database/sql"
	"fmt"
	"go-course/database"
	"time"

	_ "github.com/go-sql-driver/mysql"
)

const TIME_LAYOUT = "2006-01-02"

var (
	loc *time.Location
)

func init() {
	loc, _ = time.LoadLocation("Asia/Shanghai")
}

// insert 插入数据
func insert(db *sql.DB) {
	// 一条sql,插入2行记录
	res, err := db.Exec("insert into student (name,province,city,enrollment) values ('小明', '深圳', '深圳', '2021-04-18'), ('小红', '上海', '上海', '2021-04-26')")
	database.CheckError(err)
	lastId, err := res.LastInsertId() // ID自增,用过的id(即使对应的行已delete)不会重复使用。如果使用单个INSERT语句将多行插入到表中,则LastInsertId是第一条数据使用的id
	database.CheckError(err)
	fmt.Printf("after insert last id %d\n", lastId)
	rows, err := res.RowsAffected() // 插入2行,所以影响了2行
	database.CheckError(err)
	fmt.Printf("insert affect %d row\n", rows)
}

// replace 插入(覆盖)数据
func replace(db *sql.DB) {
	// 由于name字段上有唯一索引,insert重复的name会报错,而使用replace会先删除,再插入
	res, err := db.Exec("replace into student (name,province,city,enrollment) values ('小明', '深圳', '深圳', '2021-04-18'), ('小红', '上海', '上海', '2021-04-26')")
	database.CheckError(err)
	lastId, err := res.LastInsertId() // ID自增,用过的id(即使对应的行已delete)不会重复使用
	database.CheckError(err)
	fmt.Printf("after insert last id %d\n", lastId)
	rows, err := res.RowsAffected() // 先删除,后插入,影响了4行
	database.CheckError(err)
	fmt.Printf("insert affect %d row\n", rows)
}

// update 修改数据
func update(db *sql.DB) {
	// 不同的city加不同的分数
	res, err := db.Exec("update student set score=score+10 where city='上海'") // 上海加10分
	database.CheckError(err)
	lastId, err := res.LastInsertId() // 0, 仅插入操作才会给LastInsertId赋值
	database.CheckError(err)
	fmt.Printf("after update last id %d\n", lastId)
	rows, err := res.RowsAffected() // where city=?命中了几行,就会影响几行
	database.CheckError(err)
	fmt.Printf("update affect %d row\n", rows)
}

// query 查询数据
func query(db *sql.DB) {
	rows, err := db.Query("select id,name,city,score from student where id>2") // 查询得分大于2的记录
	database.CheckError(err)
	// 没有数据或发生error时返回false
	for rows.Next() {
		var id int
		var score float32
		var name, city string
		err = rows.Scan(&id, &name, &city, &score) // 通过scan把db里的数据赋给go变量
		database.CheckError(err)
		fmt.Printf("id=%d, score=%.2f, name=%s, city=%s \n", id, score, name, city)
	}
}

// delete 删除数据
func delete(db *sql.DB) {
	res, err := db.Exec("delete from student where id>13") // 删除得分大于13的记录
	database.CheckError(err)
	rows, err := res.RowsAffected() // where id>13命中了几行,就会影响几行
	database.CheckError(err)
	fmt.Printf("delete affect %d row\n", rows)
}

5. stmt

首先看两个sql注入攻击的例子

sql = "select username,password from user where username='" + username + "' and password='" + password + "'"; 

变量username和password从前端输入框获取,如果用户输入的username为lily, password为aaa’ or ‘1’='1,则完整的sql为select username,password from user where username=‘lily’ and password=‘aaa’ or ‘1’=‘1’,会返回表里的所有记录,如果记录数大于0就允许登录,则lily的账号被盗

sql="insert into student (name) values ('"+username+" ') ";

变量username从前端输入框获取,如果用户输入的username为lily’); drop table student;–,完整sql为insert into student (name) values (‘lily’); drop table student;–‘),通过注释符–屏蔽掉了末尾的’),删除了整个表

防止sql注入的方法:

  • 前端输入要加正则校验、长度限制
  • 对特殊符号(<>&*; '"等)进行转义或编码转换,Go的text/template 包里面的HTMLEscapeString函数可以对字符串进行转义处理
  • 不要将用户输入直接嵌入到sql语句中,而应该使用参数化查询接口,如Prepare、Query、Exec(query string, args …interface{})
  • 使用专业的SQL注入检测工具进行检测,如sqlmap、SQLninja
  • 避免网站打印出SQL错误信息,以防止攻击者利用这些错误信息进行SQL注入

参数化查询

db.Where("merchant_id = ?", merchantId)

拼接sql

db.Where(fmt.Sprintf("merchant_id = %s", merchantId))

定义一个sql模板

stmt, err := db.Prepare("update student set score=score+? where city=?")

多次使用模板

res, err := stmt.Exec(10, "上海")
res, err = stmt.Exec(9, "深圳") 

SQL预编译
DB执行sql分为3步:

  • 词法和语义解析
  • 优化SQL语句,制定执行计划
  • 执行并返回结果

SQL预编译技术是指将用户输入用占位符?代替,先对这个模板化的sql进行预编译,实际运行时再将用户输入代入,除了可以防止SQL注入,还可以对预编译的SQL语句进行缓存,之后的运行就省去了解析优化SQL语句的过程

stmt_demo.go

// update 通过stmt修改数据
func update(db *sql.DB) {
	// 不同的city加不同的分数
	stmt, err := db.Prepare("update student set score=score+? where city=?")
	database.CheckError(err)
	// 执行修改操作通过stmt.Exec,执行查询操作通过stmt.Query
	res, err := stmt.Exec(10, "上海") // 上海加10分
	database.CheckError(err)
	res, err = stmt.Exec(9, "深圳") // 深圳加9分
	database.CheckError(err)
	lastId, err := res.LastInsertId() // 0, 仅插入操作才会给LastInsertId赋值
	database.CheckError(err)
	fmt.Printf("after update last id %d\n", lastId)
	rows, err := res.RowsAffected() // where city=?命中了几行,就会影响几行
	database.CheckError(err)
	fmt.Printf("update affect %d row\n", rows)
}

// query 通过stmt查询数据
func query(db *sql.DB) {
	stmt, err := db.Prepare("select id,name,city,score from student where id>?")
	database.CheckError(err)
	// 执行修改操作通过stmt.Exec,执行查询操作通过stmt.Query
	rows, err := stmt.Query(2) // 查询得分大于2的记录
	database.CheckError(err)
	// 没有数据或发生error时返回false
	for rows.Next() {
		var id int
		var score float32
		var name, city string
		err = rows.Scan(&id, &name, &city, &score) //通过scan把db里的数据赋给go变量
		database.CheckError(err)
		fmt.Printf("id=%d, score=%.2f, name=%s, city=%s \n", id, score, name, city)
	}
}

遍历一张表的正确姿势:

// traverse 借助于主健自增ID,通过where id>maxid遍历表
func traverse(db *sql.DB) {
	var maxid int
	begin := time.Now()
	stmt, _ := db.Prepare("select id,name,province from student where id>? limit 100") //limit m,n  limit 0,n
	for i := 0; i < 100; i++ {
		t0 := time.Now()
		rows, _ := stmt.Query(maxid)
		fmt.Println(i, time.Since(t0))

		for rows.Next() {
			var id int
			var name string
			var province string
			rows.Scan(&id, &name, &province)
			if id > maxid {
				maxid = id
			}
		}
	}
	fmt.Println("total", time.Since(begin))
}

6. SQLBuilder

6.1 Go-SQLBuilder

Go-SQLBuilder是一个用于创建SQL语句的工具函数库,提供一系列灵活的、与原生SQL语法一致的链式函数

安装方式

go get -u github.com/parkingwang/go-sqlbuilder

Go-SQLBuilder通过函数链来构造sql语句,比如select语句的构造

func query() {
	sql := gsb.NewContext().Select("id", "name", "score", "city").
		From("student").
		OrderBy("score").DESC().
		Column("name").ASC().
		Limit(10).Offset(20).
		ToSQL()
	fmt.Println(sql)
}

为什么需要SQLBuilder?

  • 写一句很长的sql容易出错,且出错后不好定位
  • 函数式编程可以直接定位到是哪个函数的问题
  • 函数式编程比一长串sql更容易编写和理解

6.2 Gendry

Gendry是一个用于辅助操作数据库的Go包,基于go-sql-driver /mysql,它提供了一系列的方法来为你调用标准库database/sql中的方法准备参数

安装方式

go get –u github.com/didi/gendry

Gendry倾向于把复杂的筛选条件放在map中,并且跟stmt技术结合得比较紧密

func query(db *sql.DB) {
	where := map[string]interface{}{
		"city":     []string{"北京", "上海", "杭州"},
		"score<":   30,
		"addr":     builder.IsNotNull,
		"_orderby": "score desc",
	}
	table := "student"
	fields := []string{"id", "name", "city", "score"}
	//准备stmt模板
	template, values, err := builder.BuildSelect(table, where, fields)
	database.CheckError(err)
	//执行stmt模板
	rows, err := db.Query(template, values...)
	database.CheckError(err)
	for rows.Next() {
		var id int
		var name, city string
		var score float32
		err := rows.Scan(&id, &name, &city, &score)
		database.CheckError(err)
		fmt.Printf("%d %s %s %.2f\n", id, name, city, score)
	}
}

6.3 自行实现SQLBuilder

作为练习,我们自行实现一个SQLBuilder,它最终应该支持如下函数链式的编程风格

sql := NewSelectBuilder("student").Column("id,name,city").
	Where("id>0").
	And("city='郑州'").
	Or("city='北京'").
	OrderBy("score").Desc().
	Limit(0, 10).ToString()`

Builder设计模式的精髓在于Builder对象的方法还是返回一个Builder,首先定义一个Builder接口

type Builder interface {
	toString() string
	getPrev() Builder
}

select、where、limit、orderby这些都是Builder,这里详细讲解WhereBuilder的设计与实现

type WhereBuilder struct {
	sb strings.Builder // 拼接where条件字符串
	orderby *OrderByBuilder // where后面可能会接order by
	limit *LimitBuilder	// where后面可能会接limit
	prev Builder // where前面是select
}

WhereBuilder中的sb负责当下,orderby和limit负责维护后面节点,prev负责维护前面的节点
where表达式中可能包含and和or,把它们定义为WhereBuilder的方法,并且这两个方法依赖返回WhereBuilder自身

func (self *WhereBuilder) And(condition string) *WhereBuilder {
	self.sb.WriteString(" and ")
	self.sb.WriteString(condition)
	return self
}
func (self *WhereBuilder) Or(condition string) *WhereBuilder {
	self.sb.WriteString(" or ")
	self.sb.WriteString(condition)
	return self
}

where表达式后面可能会跟order by表达式,把OrderBy定义为WhereBuilder的方法,该方法返回OrderByBuilder

func (self *WhereBuilder) OrderBy(column string) *OrderByBuilder {
	orderby := newOrderByBuilder(column)
	self.orderby = orderby
	orderby.prev = self
	return orderby
}

函数链上的最后一个Builder调用ToString()方法生成写成的sql语句

func (self *LimitBuilder) ToString() string {
	var root Builder
	root = self
	for root.getPrev() != nil {
		root = root.getPrev() // 递归找到最前面的Builder
	}
	return root.toString() // 在最前面的Builder(即SelectBuilder)上调用toString()
}

每个Builder都有toString()方法,以WhereBuilder为例,它在构造函数里把where表达式放入sb成员变量里,WhereBuilder在toString()方法里调用where后面的节点的toString()方法

func newWhereBuilder(condition string) *WhereBuilder {
	builder := &WhereBuilder{}
	builder.sb.WriteString(" where ")
	builder.sb.WriteString(condition)
	return builder
}
func (self *WhereBuilder) toString() string {
	// 递归调用后续Builder的ToString()
	if self.orderby != nil {
		self.sb.WriteString(self.orderby.toString())
	}
	if self.limit != nil {
		self.sb.WriteString(self.limit.toString())
	}
	return self.sb.String()
}

7. GORM

ORM即Object Relational Mapping,对象关系映射
Relational指各种sql类的关系型数据库,Object指面向对象编程(object-oriented programming)中的对象
ORM在数据库记录和程序对象之间做一层映射转换,使程序中不用再去编写原生SQL,而是面向对象的思想去编写类、对象、调用相应的方法来完成数据库操作

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

GORM是一个全能的、友好的、基于golang的ORM库
GORM 倾向于约定,而不是配置。默认情况下,GORM 使用ID作为主键,使用结构体名的【蛇形复数】作为表名,字段名的【蛇形】作为列名,并使用CreatedAt、UpdatedAt字段追踪创建、更新时间
GORM完全是在操作struct,看不到sql的影子

type Student struct {
	Id         int    `gorm:"column:id;primaryKey"`
	Name       string `gorm:"column:name"`
	Province   string
	City       string    `gorm:"column:city"`
	Address    string    `gorm:"column:addr"`
	Score      float32   `gorm:"column:score"`
	Enrollment time.Time `gorm:"column:enrollment;type:date"`
}
student := Student{
	Name: "光绪", 
	Province: "北京", 
	City: "北京", 
	Score: 38, 
	Enrollment: time.Now()
}
db.Create(&student)

GORM同时支持使用函数链的方式写sql语句

func query(db *gorm.DB) {
	// 返回一条记录
	var student Student
	db.Where("city=?", "郑州").First(&student) // 有First就有Last
	fmt.Println(student.Name)
	fmt.Println()
	// 返回多条记录
	var students []Student
	db.Where("city=?", "郑州").Find(&students)
	for _, ele := range students {
		fmt.Printf("id=%d, name=%s\n", ele.Id, ele.Name)
	}
	fmt.Println()
	students = []Student{} // 清空student,防止前后影响
	db.Where("city in ?", []string{"郑州", "北京"}).Find(&students)
	for _, ele := range students {
		fmt.Printf("id=%d, name=%s\n", ele.Id, ele.Name)
	}
	fmt.Println("============where end============")
	// 根据主键查询
	student = Student{} // 清空student,防止前后影响
	students = []Student{}
	db.First(&student, 1)
	fmt.Println(student.Name)
	fmt.Println()
	db.Find(&students, []int{1, 2, 3})
	for _, ele := range students {
		fmt.Printf("id=%d, name=%s\n", ele.Id, ele.Name)
	}
	fmt.Println("============primary key end============")
	// 根据map查询
	student = Student{}
	students = []Student{}
	db.Where(map[string]interface{}{"city": "郑州", "score": 0}).Find(&students)
	for _, ele := range students {
		fmt.Printf("id=%d, name=%s\n", ele.Id, ele.Name)
	}
	fmt.Println("============map end============")
	// OR查询
	student = Student{}
	students = []Student{}
	db.Where("city=?", "郑州").Or("city=?", "北京").Find(&students)
	for _, ele := range students {
		fmt.Printf("id=%d, name=%s\n", ele.Id, ele.Name)
	}
	fmt.Println("============or end============")
	// order by
	student = Student{}
	students = []Student{}
	db.Where("city=?", "郑州").Order("score").Find(&students)
	for _, ele := range students {
		fmt.Printf("id=%d, name=%s\n", ele.Id, ele.Name)
	}
	fmt.Println("============order end============")
	// limit
	student = Student{}
	students = []Student{}
	db.Where("city=?", "郑州").Order("score").Limit(1).Offset(0).Find(&students)
	for _, ele := range students {
		fmt.Printf("id=%d, name=%s\n", ele.Id, ele.Name)
	}
	fmt.Println("============limit end============")
	// 选择特定的字段
	student = Student{}
	db.Select("name").Take(&student) // Take从结果中取一个,不保证是第一个或最后一个
	fmt.Printf("name=%s, province=%s\n", student.Name, student.Province) // 只select了name,所以province是空的
}

8. Go操作MongoDB

NoSQL泛指非关系型数据库,如mongo、redis、HBase
mongo使用高效的二进制数据存储,文件存储格式为 BSON (一种json的扩展,比json性能更好,功能更强大),MySQL中表的概念在mongo里叫集合(collection), MySQL中行的概念在mongo中叫文档(document),一个文档看上去像一个json

安装mongo前先配置yum源:vim /etc/yum.repos.d/mongodb-org-4.2.repo

[mongodb-org-4.2] 
name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.2/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc

一键安装mongo:sudo yum install -y mongodb-org
启动mongo:systemctl start mongod

mongo常用命令

use test;  切换到test库,如果没有则(创建集合时)会自动创建
db.createCollection("student");  创建collection
db.createUser({user: "tester",pwd: "123456", roles: [{role: "dbAdmin", db: "test"}]});创建用户
登录mongo --port 27017 -u "tester" -p "123456" --authenticationDatabase "test"
db.student.createIndex({"name":1});在name上创建索引,不是唯一索引
 db.student.insertOne({name:"张三",city:"北京"});
db.student.find({name:"张三"});
db.student.update({name:"张三"},{name:"张三",city:"上海"})
db.student.deleteOne({name:"张三"});

安装go mongo-driver

go get go.mongodb.org/mongo-driver
go get go.mongodb.org/mongo-driver/x/bsonx/bsoncore@v1.7.1
go get go.mongodb.org/mongo-driver/x/mongo/driver@v1.7.1
go get go.mongodb.org/mongo-driver/mongo/options@v1.7.1
go get go.mongodb.org/mongo-driver/x/mongo/driver/topology@v1.7.1
go get go.mongodb.org/mongo-driver/mongo@v1.7.1

连接db

option := options.Client().ApplyURI("mongodb://127.0.0.1:27017").
SetConnectTimeout(time.Second).//连接超时时长
SetAuth(options.Credential{Username: "tester", Password: "123456", AuthSource: "test"}) // 指定用户名和密码,AuthSource代表Database
client, err := mongo.Connect(context.Background(), option)
err = client.Ping(ctx, nil) 

注意Ping成功才代表连接成功
查询mongo

sort := bson.D{{"name", 1}} // 1升序,-1降序
filter := bson.D{{"score", bson.D{{"$gt", 3}}}} //score>3
findOption := options.Find()
findOption.SetSort(sort) // 按name排序
findOption.SetLimit(10) // 最多返回10个
findOption.SetSkip(3) // 跳过前3个
cursor, err := collection.Find(ctx, filter, findOption)
defer cursor.Close(ctx) // 关闭迭代器
for cursor.Next(ctx) {
	var doc Student
	err := cursor.Decode(&doc)
	database.CheckError(err)
	fmt.Printf("%s %s %.2f\n", doc.Name, doc.City, doc.Score)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/362842.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023美赛参赛经历分享

今天早上登录MCM: The Mathematical Contest in Modeling (comap.com)发现论文提交已经显示Received。虽然这几天连连有开学恶补的期末考试&#xff0c;但还是忙里偷闲趁着新鲜写一篇关于美赛的参赛个人感受。跟我一起打这次美赛的都是软件等专业的hxd&#xff0c;他们之前没有…

SpringBoot + Lock4j实现高性能分布式锁

1. 简介 在分布式业务开发中&#xff0c;很多场景都需要添加分布式锁。在具体实践过程中&#xff0c;研发人员都需要自行实现&#xff0c;导致实现方式不统一&#xff0c;代码风格迥异&#xff0c;难以维护。 在Mybatis-Plus生态中&#xff0c;Lock4j提供了支持redission、re…

华为OD机试 - 最大排列(C++) | 附带编码思路 【2023】

刷算法题之前必看 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12199283.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 华为OD机试题…

python--matplotlib(4)

前言 Matplotlib画图工具的官网地址是 http://matplotlib.org/ Python环境下实现Matlab制图功能的第三方库&#xff0c;需要numpy库的支持&#xff0c;支持用户方便设计出二维、三维数据的图形显示&#xff0c;制作的图形达到出版级的标准。 其他matplotlib文章 python--matpl…

Spring Cloud Gateway Nacos 实现动态路由

微服务都是互相独立的&#xff0c;假如我们的网关和其他服务都在线上已经运行了好久&#xff0c;这个时候增加了一个微服务&#xff0c;这个时候要通过网关访问的话需要通过修改配置文件来增加路由规则&#xff0c;并且需要重启项目&#xff0c;所以我们需要实现动态路由 方式一…

34. 应用监控【监控端点配置】

当一个 Spring Boot 项目运行时&#xff0c;开发者需要对 Spring Boot 项目进行实时监控来获取项目的运行情况&#xff0c;在项目出错时能够实现自动报警等。 Spring Boot 提供了actuator 来帮助开发者获取应用程序的实时运行数据。开发者可以选择使用 HTTP 端点或JMX来管理和监…

九龙证券|银行资本管理办法迎“大修” 信用风险权重法调整优化

1年期AAA中债商业银行同业存单到期收益率 日前迎来“大修”的商业银行本钱办理方法&#xff0c;在债券商场激起“涟漪”——债券商场一改此前平静态势&#xff0c;连续两日跌落。 2月21日&#xff0c;10年期国债收益率较上星期五上行2.9个基点&#xff0c;至2.919%&#xff1b…

记录charles手机端配置https的成功过程

1.百度 https://www.likecs.com/show-204025787.html https://blog.csdn.net/enthan809882/article/details/117572094?spm1001.2101.3001.6650.6&utm_mediumdistribute.pc_relevant.none-task-blog-2defaultBlogCommendFromBaiduRate-6-117572094-blog-122959902.pc_rele…

余承东:问界就是华为生态汽车,不涉及20万以下车型

今天界面新闻发布了一篇余承东的专访文章&#xff0c;谈到了外界对华为造车的质疑&#xff0c;以及回应了与赛力斯的合作&#xff0c;后续HI模式与智选车模式如何推进的话题。摘录重点如下&#xff1a;1.首先&#xff0c;继续「不造车」“华为没有必要自己下场造车。”在他看来…

Spring MVC 源码 - HandlerMapping 组件(四)之 AbstractUrlHandlerMapping

HandlerMapping 组件HandlerMapping 组件&#xff0c;请求的处理器匹配器&#xff0c;负责为请求找到合适的 HandlerExecutionChain 处理器执行链&#xff0c;包含处理器&#xff08;handler&#xff09;和拦截器们&#xff08;interceptors&#xff09;handler 处理器是 Objec…

【GO】k8s 管理系统项目[前端部分–Header]

【GO】k8s 管理系统项目[前端部分–Header] 1. 实现功能 面包屑展开关闭按钮用户信息(退出按钮) 2. 代码部分 src/layout/Layout.vue 在之前预留header位置补上 <!-- header --><el-header class"header"><el-row :gutter"20"><e…

python基于vue健身房课程预约平台

可定制框架:ssm/Springboot/vue/python/PHP/小程序/安卓均可开发 目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发3 2.2MyEclipse环境配置 4 2.3 B/S结构简介 4 2.4MySQL数据库 5 2.5 django框架 5 3 系统分析 6 3.1…

Sqoop利用Sql将mysql表_导入数据到Hive---大数据之Apache Sqoop工作笔记004

然后来看一下把数据导入到hive中去 可以去官网去看看文档,有什么参数 这里用的是hive-import对吧,然后 这里hive-overwrite是覆盖 这个hive-table staff_hive 是创建 一个hive的表是 staff_hive 然后我们先去启动一下hive 启动以后,然后我们去查一下,shot tables 可以看到 里…

Ubuntu 22.04.2 LTS安装Apollo8.0

本人硬件环境&#xff1a; CPU&#xff1a;Intel Core i7 6700 显卡&#xff08;GPU&#xff09;&#xff1a;NVIDIA GTX 3080 10G 内存&#xff1a;SAMSUNG DDR4 32GB 硬盘&#xff1a;双SSD系统盘 2T,双系统&#xff08;windows,ubuntu&#xff09; 一、安装Ubuntu 22.04…

【极海APM32替代笔记】HAL库中的SPI传输(可利用中断或DMA进行连续传输)

【极海APM32替代笔记】HAL库中的SPI传输&#xff08;可利用中断或DMA进行连续传输&#xff09; SPI 是英语Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外围设备接口。是Motorola(摩托罗拉)首先在其MC68HCXX系列处理器上定义的。 SPI&#xff0c;是一种高…

Ssh协议绑定Git服务器

1、起因在公司开发一般使用gitlab部署公司git代码管理&#xff0c;个人的代码存储在公司gitlab上就显得不合时宜了&#xff0c;所以找了gitee上来存储代码。2、经过搜索了下github.com,gitee.com 其他当然有阿里云的云效等&#xff0c;个人使用优先国内git服务器&#xff0c;理…

【Netty系列・扫盲篇】Netty从入门到学废

文章目录1. 概述1.1 Netty 的地位1.2 Netty 的优势2. Hello World2.1 目标2.2 服务器端2.3 客户端2.4 流程梳理&#x1f4a1; 提示3. 组件3.1 EventLoop&#x1f4a1; 优雅关闭演示 NioEventLoop 处理 io 事件&#x1f4a1; handler 执行中如何换人&#xff1f;演示 NioEventLo…

C# 业务单据号生成器(定义规则、获取编号、流水号)

系列文章 C#底层库–数据库访问帮助类&#xff08;MySQL版&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/126886379 C#底层库–JSON帮助类_详细&#xff08;序列化、反序列化、list、datatable&#xff09; 本文链接&#xff1a;htt…

GEE学习笔记 六十:GEE中生成GIF动画

生成GIF动画这个是GEE新增加的功能之一&#xff0c;这一篇文章我会简单介绍一下如何使用GEE来制作GIF动画。 相关API如下&#xff1a; 参数含义&#xff1a; params&#xff1a;设置GIF动画显示参数&#xff0c;详细的参数可以参考ee.data.getMapId() callback&#xff1a;回调…

基于RK3399地面测试台多参数记录仪测试平台软件设计

随着高科技技术在现代化战争中日益重要作用&#xff0c;飞行装备的研制亦从单元体制发展 到多元体制。航空装置系统在设计过程中&#xff0c;需要大量测试工作&#xff0c;尤其是需要把系统研制 和飞行试验中各部分工作状态参数实时记录&#xff0c;用以分析、改进设计。记录仪…