[golang Web开发] 2.golang web开发:操作数据库,增删改查,单元测试

news2024/11/17 6:47:29

简介

Go 语言中的 database/sql包定义了对数据库的一系列操作,database/sql/driver包定义了应被数据库驱动实现的接口,这些接口会被sql包使用.但是 Go语言没有提供任何官方的数据库驱动,所以需要导入第三方的数据库驱动,不过连接数据库之后对数据库操作的大部分代码都使用sql包

1.获取数据库连接

(1).创建一个db.go文件,导入database/sql包以及第三方驱动包

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

(2).定义两个全局变量

var (
    Db *sqlDB
    err error
)

DB结构体的说明

 (3).创建init函数,在函数体中调用sql包的Open函数获取连接

func init() {
    Db, err := sql.Open("mysql", "root:root@tcp(localhost:3306)/test")
    if err != nil {
        panic(err.Error())
    }
}    

Open函数说明 

参数dataSourceName的格式:

        数据库用户名:数据库密码@[tcp(localhost:3306)]/数据库名

完整代码: 

package utils

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

var (
   Db *sql.DB
   err error
)

func init()  {
   Db, err = sql.Open("mysql", "root:123456@/go-data")
   if err != nil {
      panic(err.Error())
   }
}

2.增删改查操作

(1).在连接test数据库中创建一个users表 

create table users (
    id int primary key auto_increment,
    username varchar(255) unique not null,
    password varchar(255) not null,
    email varchar(255)
)

(2).向users表中插入一条数据

1).创建user.go文件,文件中编写以下代码

package model

import(
    "fmt"
    "go_code/web_app/sql/utils"
)

 需要用到的database/sql包接口

 

 代码示例如下:

package model

import (
   "fmt"
   "go_code/web_app/sql/utils"
)

//User 结构体
type User struct {
   ID int
   Name string
   Password string
   Email string
}
//AddUser 添加User的方法一:带预编译的添加
func (user *User) AddUser() error  {
   //sql语句
   sql := "insert into user(`name`, `password`, `email`) values(?, ?, ?)"
   //预编译
   inStmt, err := utils.Db.Prepare(sql)
   if err != nil {
      fmt.Println("预编译出错", err)
      return err
   }
   //执行
   result, err2 := inStmt.Exec("admin", "123456", "admin@qq.com")
   if err2 != nil {
      fmt.Println("执行出错", err2)
      return err2
   }
   Id, err3 := result.LastInsertId()
   if err3 != nil {
      fmt.Println("插入后返回的自增id错误", err3)
      return err3
   }
   fmt.Println("插入成功, 返回的id=", Id)
   return nil
}


//AddUser 添加User的方法二:不带预编译,直接执行的添加
func (user *User) AddUser2() error  {
   //sql语句
   sql := "insert into user(name, password, email) values(?, ?, ?)"
   //执行
   result, err := utils.Db.Exec(sql, "admin2", "123456", "admin2@qq.com")
   if err != nil {
      fmt.Println("执行出错", err)
      return err
   }
   Id, err2 := result.LastInsertId()
   if err2 != nil {
      fmt.Println("插入后返回的自增id错误", err2)
      return err2
   }
   fmt.Println("插入成功, 返回的id=", Id)
   return nil
}

3.单元测试

(1).简介

顾名思义,单元测试(unit test ) ,就是一种为验证单元的正确性而设置的自动化测试,一个单元就是程序中的一个模块化部分、一般来说,一个单元通常会与程序中的一个函数或者一个方法相对应,但这并不是必须的.Go的单元测试需要用到 testing 包以及go test 命令,而且对测试文件也有以下要求:

        1).被测试的源文件和测试文件必须位于同一个包下

        2).测试文件必须要以_test.go结尾

                虽然Go对测试文件_test.go的前缀没有强制要求,不过一般都设置为被测试的文件的文件名,如:要对user.go进行测试,那么测试文件的名字通常设置为user_test.go

         3).测试文件中的测试函数为TestXxx(t *testing.T)

                其中 Xxx 的首字母必须是大写的英文宇母

                函数参数必须是 test.T的指针类型(如果是 Benchmark 测试则参数是testing.B的指针类型)

测试代码如下:

package model

import (
   "fmt"
   "testing"
)
//执行测试: go test, 查看测试的详细信息: go test -v
//TestMain()函数可以在测试函数执行之前做一些其他操作
func TestMain(m *testing.M)  {
   fmt.Println("测试开始")
   //通过m.Run()来执行测试函数
   m.Run()
}
func TestUser(t *testing.T)  {
   fmt.Println("开始测试User中的方法")
   //通过t.Run()来执行子测试函数
   t.Run("测试添加用户", testAddUser)
}

//如果函数名不是Test,那么该函数默认不执行,可以将它设置成一个子测试函数来执行
//func TestAddUser(t *testing.T)  {
func testAddUser(t *testing.T)  {
   fmt.Println("添加测试用户")
   user := &User{}
   //调用添加用户方法
   user.AddUser()
   user.AddUser2()
}

user.go: 

package model

import (
   "fmt"
   "go_code/web_app/sql/utils"
)

//User 结构体
type User struct {
   ID       int
   Name     string
   Password string
   Email    string
}

//AddUser 添加User的方法一:带预编译的添加
func (user *User) AddUser() error {
   //sql语句
   sql := "insert into user(`name`, `password`, `email`) values(?, ?, ?)"
   //预编译
   inStmt, err := utils.Db.Prepare(sql)
   if err != nil {
      fmt.Println("预编译出错", err)
      return err
   }
   //执行
   result, err2 := inStmt.Exec("admin", "123456", "admin@qq.com")
   if err2 != nil {
      fmt.Println("执行出错", err2)
      return err2
   }
   Id, err3 := result.LastInsertId()
   if err3 != nil {
      fmt.Println("插入后返回的自增id错误", err3)
      return err3
   }
   fmt.Println("插入成功, 返回的id=", Id)
   return nil
}

//AddUser 添加User的方法二:不带预编译,直接执行的添加
func (user *User) AddUser2() error {
   //sql语句
   sql := "insert into user(name, password, email) values(?, ?, ?)"
   //执行
   result, err := utils.Db.Exec(sql, "admin2", "123456", "admin2@qq.com")
   if err != nil {
      fmt.Println("执行出错", err)
      return err
   }
   Id, err2 := result.LastInsertId()
   if err2 != nil {
      fmt.Println("插入后返回的自增id错误", err2)
      return err2
   }
   fmt.Println("插入成功, 返回的id=", Id)
   return nil
}

//GetUserById 根据用户id从数据中查询一条记录
func (user *User) GetUserById() (*User, error) {
   //sql语句
   sql := "select id, name, password, email from user where id = ?"
   //执行
   row := utils.Db.QueryRow(sql, user.ID)
   //声明
   var id int
   var name string
   var password string
   var email string
   err := row.Scan(&id, &name, &password, &email)
   if err != nil {
      return nil, err
   }
   u := &User{
      ID:       id,
      Name:     name,
      Password: password,
      Email:    email,
   }
   return u, nil
}

//GetUsers 获取数据库中所有数据
func (user *User) GetUsers() ([]*User, error) {
   //sql语句
   sql := "select id, name, password, email from user"
   //执行
   rows, err := utils.Db.Query(sql)
   if err != nil {
      return nil, err
   }
   //定义一个User切片
   var users []*User
   //循环rows
   for rows.Next() {
      //声明
      var id int
      var name string
      var password string
      var email string
      err := rows.Scan(&id, &name, &password, &email)
      if err != nil {
         return nil, err
      }
      u := &User{
         ID:       id,
         Name:     name,
         Password: password,
         Email:    email,
      }
      users = append(users, u)
   }
   return users, nil
}

user_test.go: 

package model

import (
   "fmt"
   "testing"
)

//执行测试: go test, 查看测试的详细信息: go test -v
//TestMain()函数可以在测试函数执行之前做一些其他操作
func TestMain(m *testing.M) {
   fmt.Println("测试开始")
   //通过m.Run()来执行测试函数
   m.Run()
}
func TestUser(t *testing.T) {
   fmt.Println("开始测试User中的方法")
   //通过t.Run()来执行子测试函数
   //t.Run("测试添加用户", testAddUser)
   //t.Run("测试获取用户", testGetUserById)
   t.Run("测试获取所有用户", testGetUsers)
}

//如果函数名不是Test,那么该函数默认不执行,可以将它设置成一个子测试函数来执行
//func TestAddUser(t *testing.T)  {
func testAddUser(t *testing.T) {
   fmt.Println("添加测试用户")
   user := &User{}
   //调用添加用户方法
   err := user.AddUser()
   if err != nil {
      fmt.Println(err)
   }
   err2 := user.AddUser2()
   if err2 != nil {
      fmt.Println(err2)
   }
}

//测试获取用户信息
func testGetUserById(t *testing.T) {
   fmt.Println("测试查询一条记录")
   user := &User{
      ID: 1,
   }
   //调用获取User的方法
   u, _ := user.GetUserById()
   fmt.Println("得到User的信息:", u)
}

//测试获取所有用户信息
func testGetUsers(t *testing.T) {
   fmt.Println("测试查询所有记录")
   user := &User{}
   //调用获取所有User的方法
   us, _ := user.GetUsers()
   //遍历切片
   for k, u := range us {
      fmt.Printf("第%d个用户信息:%v\n", k + 1, u)
   }
}

[上一节] [golang Web开发] 1.golang web开发简介以及web服务器的搭建以及http协议简介

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

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

相关文章

超经典JavaIDEA 10个插件 Java开发工程师

工欲善其事,必先利其器。 作为一名合格的程序员,合理配置我们所用的IDEA,是高效开发的必修课。而如今的插件工具也越来越好用,不仅基本具备了智能提示,还可以自动补全代码,甚至能够在查出bug的同时提供修改…

如何彻底删除硬盘数据?电脑高手也恢复不了

实用的小命令,就是彻底删除硬盘上的数据,硬盘恢复软件也恢复不了! 1.以管理员身份运行cmd窗口,打开cmd,如下图所示: 2.在命令提示窗口中,直接输入cipher /w:路径,输入这个命令加上路径即可将文件彻底删除! 可以从整个命令说明上看到是从整个卷上可用的未使用磁盘空间…

Git (2) :Git练习--分支的新建与合并

一.首先有个问题 ? 在进行git练习前,有个问题需要提下。。。。 csdn无法登录了。 查了一下资料,是因为CSDN服务器的各地相应速度不一样,辽宁的响应是超时的,所以通过在hosts文件中指定域名http://csdnimg.cn的服务器…

机器学习之卷积操作

很多好主意一旦踏上语义鸿沟,就再也听不到。 卷积,在图像、视觉领域乃老生常谈的内容,但是对于具体工作细节仍然值得我去学习。 卷积原理 卷积,就是利用一个小的矩阵(或者更高维向量)作用于图像矩阵(或者特征矩阵),然…

Web测试、APP测试常用技巧(错过你一定会后悔)

目录 1. web元素定位七种方式 2. app元素定位3种方式 3. adb常用命令 4. 键盘操作常用函数 5. 鼠标操作常用函数 6. apppium: 7. fixture 1. web元素定位七种方式 优先使用的6种 find_element_by_id (返回一个元素)find_element(s)_by_class_name (根据类名…

2023-02-01 pthread线程局部数据-记录

摘要: pthread线程局部数据-记录 参考: https://www.akkadia.org/drepper/tls.pdf https://en.wikipedia.org/wiki/Thread-local_storage https://download.csdn.net/download/adofsauron/87408865 测试代码: 示例一: #include<stdio.h> #include<stdlib.h> #…

pip install timeout错误解决方案

大家好&#xff0c;我是爱编程的喵喵。双985硕士毕业&#xff0c;现担任全栈工程师一职&#xff0c;热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结…

java spring Bean生命周期

首先 要搞清楚大概念 什么是生命周期&#xff1f; 学过vue和react的前端会有概念 简单说 就是一个对象从创建到销毁的整个过程 那么 bean的生命周期 我们先文字描述 然后再看效果 第一 阶段 通过构造器创建bean实例 就是找到bean对象配置的 类中的无惨构造 创建对象 第二阶段…

React学习笔记-(Bilibili李立超)

写法的变更 之前 const divNode <div>你好,React</div> ReactDOM.render(divNode,document.getElementById(root))会警告 现在 <script type"text/babel">const divNode <div>你好,React</div>const root ReactDOM.createRoot(…

【PHP 随记】—— laravel 项目环境搭建

&#x1f449;总目录&#x1f448;\large\colorbox{skyblue}{&#x1f449;总目录&#x1f448;}&#x1f449;总目录&#x1f448;​ 文章目录1、安装 laravel 以及 phpstorm 开发插件2、配置虚拟主机与绑定 hosts 文件① 配置虚拟主机② hosts 绑定③ 验证3、配置数据库① 配…

【MyBatis持久层框架】使用Java注解完成CRUD详细解读

文章目录1. 前言2. 实战案例2.1 准备工作2.2 编写接口方法2.3 映射SQL语句2.4 编写测试方法3. SQL语句构建器4. 总结1. 前言 之前我们通过 XML 配置文件的方式映射 sql 语句&#xff0c;将 sql 语句与 Java 代码分离&#xff0c;大大的提高了开发的效率并且解决了 JDBC 原生方…

MySQL - 为什么索引存储要用B+树,用链表不行吗?

MySQL - 为什么索引存储要用B树&#xff0c;用链表不行吗&#xff1f; 时间&#xff1a;2023年2月1日22:19:09 一、先来比较一下链表和树&#xff1f; 二、为什么数据库索引要用B树&#xff1f; 为什么要用索引&#xff0c;数据直接Load到内存里查不可以吗&#xff1f;&#…

Hive最全总结,学习与面试,收藏这一篇就够了!

Hive基础概念和用途 Hive是Hadoop下的顶级 Apache项目&#xff0c;早期的Hive开发工作始于2007年的 Facebook。 ⬛ Apache Hive是一款建立在Hadoop之上的开源数据仓库系统&#xff0c;可以将存储在Hadoop文件中的结构化、半结构化 数据文件映射为一张数据库表&#xff0c;基…

操作系统(day05)-- 进程调度、调度算法

文章目录进程调度&#xff08;低级调度&#xff09;进程调度的时机进程调度的方式调度算法的评价指标FCFS&#xff0c;SJF&#xff0c;HRRN调度算法先来先服务&#xff08;FCFS&#xff09;短作业优先&#xff08;SJF&#xff09;高响应比优先&#xff08;HRRN&#xff09;进程…

从0开始用hooks搭建一个事件待办的demo(一)

需求一&#xff1a;实现header&#xff0c;点击加号展示input&#xff0c;再次点击隐藏input 分析&#xff1a; 首先&#xff0c;需要两个子组件header和addInput&#xff1b; header组件负责展示图一的内容&#xff0c;给加号添加一个点击事件&#xff0c;来触发展示input的函…

zookeeper源码分享五 --- 数据结构

zookeeper 内存数据结构 zookeeper在内存当中是有一份完整的数据&#xff0c;底层数据结构是基于hashMap去实现的。 在map的key是path&#xff0c;value是具体节点信息(DataNode)。 在map的顶层中有所有节点的path信息&#xff0c;每个节点都要子节点的path(不是具体的节点信息…

图的存储与遍历

目录 一.邻接矩阵 1.1概念介绍 1.2代码示例 1.3代码测试 二.邻接表 2.1概念介绍 2.2代码示例&#xff1a; 2.3代码测试 三.遍历 3.1广度优先遍历&#xff08;BFS&#xff09; 3.1.1邻接表&#xff08;BFS&#xff09; 3.1.2邻接矩阵&#xff08;BFS&#xff09; 3.2深…

不是计算机专业的,想学Java,能学得会吗?

看到这个问题&#xff0c;想到昨天一位机电一体化专业的同学来咨询了Java和云计算两个专业的培训情况。一来就问&#xff1a;“我这种情况能学得会吗&#xff0c;之前也没接触过计算机方面的专业&#xff0c;就是玩玩游戏&#xff0c;正常上网之类的操作&#xff1b;但我是真的…

【数据结构与算法】图的基本概念 | 邻接矩阵和邻接表 | 广度优先遍历和深度优先遍历

&#x1f320;作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《数据结构与算法要啸着学》 &#x1f387;座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;…

ElasticSearc写入查询性能优化总结

文章目录前言1、bulk批量写入2、多线程写入3、修改索引刷新时间4、修改merge参数以及线程数6、index buffer7、磁盘间的任务均衡8、Mapping优化8.1、自动生成docID(避免ES对自定义ID验证的操作)8.2、调整字段Mapping8.3、调整_source字段8.4、禁用_all8.5、禁用Norms8.6、index…