当前位置: 首页 > news >正文

Go语言实现JDBC

Go语言操作数据库

Go语言提供了关于数据库的操作,包下有sql/driver

该包用来定义操作数据库的接口,这保证了无论使用哪种数据库,操作方式都是相同的;

准备工作:

下载驱动

需要在代码所在文件夹下执行相应的命令

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

PS D:\GolandData> go get github.com/go-sql-driver/mysql
go: downloading github.com/go-sql-driver/mysql v1.7.1
go: added github.com/go-sql-driver/mysql v1.7.1

安装驱动

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

安装之后检查go.mod文件

在这里插入图片描述

Go提供了sql包,但是没有指定是哪一个数据库的,用于访问特定数据库的方法交给了数据库驱动实现;

匿名导入包

匿名导入包——只导入包但是不使用包内的类型和数据,使用匿名的方式(在包路径前添加下画线“_”)导入MySQL驱动。

为什么需要匿名导包—开发者不应该直接使用导入的驱动包所提供的方法,而应该使用sql.DB对象所提供的统一方法;

在导入一个数据库驱动后,该驱动会自行初始化并注册到Golang的database/sql上下文中

连接数据库

连接数据库基础API

Driver接口中有一个方法Open()

/*数据库驱动程序可以实现DriverContext访问在一个连接池中只解析一次名称而不是每个连接一次。*/
type Driver interface {/* Open返回到数据库的新连接。该名称是驱动程序特定格式的字符串。 Open可能返回一个缓存的连接(先前的一个关闭的),但这样做是不必要的;SQL包维护一个空闲连接池,以便有效地重用。返回的连接一次只被一个线程使用。*/Open(name string) (Conn, error)
}

sql包中有一个open(driverName, dataSourceName string)方法
该方法打开一个数据库连接,

func Open(driverName, dataSourceName string) (*DB, error) {driversMu.RLock()//这里说明一个线程用一个连接driveri, ok := drivers[driverName]driversMu.RUnlock()if !ok {return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)}if driverCtx, ok := driveri.(driver.DriverContext); ok {connector, err := driverCtx.OpenConnector(dataSourceName)if err != nil {return nil, err}return OpenDB(connector), nil}return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil
}

参数释义----即连接数据库三要素

  • driverName–数据库驱动名
  • dataSourceName:数据库连接信息,数据库地址,用户名.密码, 数据库名等信息

由open()源代码可以看到,sql.Open()返回的sql.DB对象是并发安全的,即每次只能一个Goroutine使用一个,所以高并发下如果没有及时关闭不需要的连接,就会导致系统资源耗尽;

sql.DB的设计初衷是为长连接设计的,不宜频繁开关;

比较好的做法是,为每个不同的datastore建一个DB对象,保持这些对象打开
如果需要短连接(一次连接一次数据交互),就把DB作为参数传入function,而不要在function中开关。

CURD操作

来一段代码Demo

数据库查询

type BookInfo struct {BookId, BookName, BookPublish, BookKind stringBookPrice                               float64BookCount                               int
}func (b *BookInfo) DatabaseMysql() {//db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/gavin?charset=utf8") //返回*DB, errordb, err := sql.Open("mysql", "root:123456@tcp(172.21.114.22:3306)/gavin?charset=utf8") //返回*DB, errorif err != nil {fmt.Println("打开失败")fmt.Println(err.Error())return}fmt.Println("打开成功")fmt.Printf("%T\n", db)queryStr := `select * from bookstore ;` //sql语句//Exec执行一个不返回任何行的查询。//args用于查询中的任何占位参数。  看样子不能用这个方法//exec, err := db.Exec(queryStr)         //返回Result ,err//fmt.Printf("类型%T \n 值 %v", exec, exec) // nil,nil//构建一个DB对象queryResult, err := db.Query(queryStr) //返回 *Rows, errorif err != nil {fmt.Println(err.Error())return}for queryResult.Next() {queryResult.Scan(&b.BookId, &b.BookName, &b.BookPublish, &b.BookPrice, &b.BookKind, &b.BookCount)fmt.Printf("bookInfo信息: bookid: %s\t bookname: %s \t bookpublish: %s \t bookprice: %f \t bookkind: %s bookcount %d \n", b.BookId, b.BookName, b.BookPublish, b.BookPrice, b.BookKind, b.BookCount)}db.Close()}func main() {b := BookInfo{}b.DatabaseMysql()
}

获得的结果:

在这里插入图片描述

我们可以看到代码的基本思路跟java一样,go是定义一个结构体用于接收数据库中的数据,然后我们需要掌握下面的几个函数用于处理数据库数据;最后关闭数据库连接

  • 使用db.Query()来发送查询到数据库,获取结果集Rows,并检查错误。
  • 使用rows.Next()作为循环条件,迭代读取结果集。
  • 使用rows.Scan从结果集中获取一行结果。
  • 使用rows.Err()在退出迭代后检查错误。
  • 使用rows.Close()关闭结果集,释放连接。

rows.Scan()方法的参数顺序很重要,必须和查询结果的column相对应(数量和顺序都需要一致)

插入数据

// 插入
func (b *BookInfo) insertData() {//连接数据库db, err := sql.Open("mysql", "root:123456@tcp(172.21.114.22:3306)/gavin?charset=utf8")chkERR(err)insertStr := `insert into bookstore VALUES("1024","Go并发实践","泉城出版社", 168.8,"计算机",198)`db.Exec(insertStr)chkERR(err)//_, err = exec.RowsAffected() //返回影响的行数,并不是所有数据库都支持,defer db.Close()
}

更新数据

// 更新
func (b *BookInfo) updateData() {db, err := sql.Open("mysql", "root:123456@tcp(172.21.114.22:3306)/gavin?charset=utf8")chkERR(err)updateStr := `update bookstore set bookprice=109 where bookname="Go并发实践"`exec, err := db.Exec(updateStr) //如果操作成功,返回affected, err := exec.RowsAffected()fmt.Println("update影响行数-->", affected)checkError(err)defer db.Close()
}

删除数据

// 删除
func (b *BookInfo) deleteData() {db, err := sql.Open("mysql", "root:123456@tcp(172.21.114.22:3306)/gavin?charset=utf8")chkERR(err)deleteStr := `delete from bookstore where bookprice>100 `exec, err := db.Exec(deleteStr)affected, err := exec.RowsAffected()fmt.Println("影响行数:", affected)defer db.Close()}

以上操作数据库的方式很容易就会产生sql注入

为此go也为我们提供了预编译的方式来操作数据库;


// 预编译的方式插入数据
func preInsert(book BookInfo) (int64, error) {db, err := sql.Open("mysql", "root:955945@tcp(172.21.114.22:3306)/gavin?")chkERR(err)queryStr := `insert into bookstore values (?,?,?,?,?,?)`//返回一个预编译的对象prepare, err := db.Prepare(queryStr) //*Stmt, errorchkERR(err)exec, err := prepare.Exec(book.BookId, book.BookName, book.BookPublish, book.BookPrice, book.BookKind, book.BookCount)affected, err := exec.RowsAffected() //返回受影响的行数fmt.Println("受影响的行数--->>", affected)defer db.Close()if err != nil {return -1, err}return affected, nil
}
func main() {b := BookInfo{BookId:      "1096",BookName:    "大雨倾盆",BookPublish: "烟台出版社",BookKind:    "小说",BookPrice:   56.5,BookCount:   100,}insert, err := preInsert(b)if err != nil {return}fmt.Println(insert)
}

结果:
在这里插入图片描述
数据库数据:
在这里插入图片描述
预编译参数用? 来表示

func preQuery(bookname string) {db, err := sql.Open("mysql", "root:955945@tcp(172.21.114.22:3306)/gavin?")chkERR(err)queryStr := `select * from bookstore where BookName=? ;`prepare, err := db.Prepare(queryStr)query, err := prepare.Query(bookname) //*Rows, errorb := new(BookInfo)for query.Next() {query.Scan(&b.BookId, &b.BookName, &b.BookPublish, &b.BookPrice, &b.BookKind, &b.BookCount)fmt.Println(*b)}defer query.Close()
}
func main() {preQuery("大雨倾盆")
}

db.Query()会从数据库连接池中获取一个连接,这个底层连接在结果集(rows)未关闭前会被标记为处于繁忙状态。当遍历读到最后一条记录时,会发生一个内部EOF错误,自动调用rows.Close()。但如果出现异常,提前退出循环,rows不会关闭,连接不会回到连接池中,连接也不会关闭,则此连接会一直被占用。因此通常使用defer rows.Close()来确保数据库连接可以正确放回到连接池中。

在实际开发中应尽量封装 curd这些方法;

但是们实际开发时并不会按照上面的方式去开发,而是借助框架去更快的实现CURD,所以后面要学习Beego框架

相关文章:

Go语言实现JDBC

Go语言操作数据库 Go语言提供了关于数据库的操作,包下有sql/driver 该包用来定义操作数据库的接口,这保证了无论使用哪种数据库,操作方式都是相同的; 准备工作: 下载驱动 需要在代码所在文件夹下执行相应的命令 go get github.com/go-sql-driver/mys…...

ubuntu修改环境变量的几种方法

ubuntu修改环境变量的几种方法 有多种方法可以修改Ubuntu系统的环境变量,包括: 临时修改环境变量:在终端中使用export命令可以临时修改环境变量。例如,要将PATH环境变量添加到新目录,可以运行以下命令: …...

基于html+css的图展示95

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…...

数据库基础——5.运算符

这篇文章我们来讲一下SQL语句中的运算符操作。 说点题外话:SQL本质上也是一种计算机语言,和C,java一样的,只不过SQL是用来操作数据库的。在C,java中也有运算符,这两种语言中的运算符和数学中的运算符差距不…...

JMeter 性能测试基本过程及示例

jmeter 为性能测试提供了一下特色: 2023年最新出炉性能测试教程,真实企业性能压测全流程项目实战训练大合集!_哔哩哔哩_bilibili2023年最新出炉性能测试教程,真实企业性能压测全流程项目实战训练大合集!共计11条视频&…...

漏洞复现 CVE-2018-2894 weblogic文件上传

vulhub weblogic CVE-2018-2894 1、 搭建好靶场,按提示访问 http://192.168.137.157:7001/console 按照给出的文档,会查看容器的日志,找到管理员用户名/密码为 weblogic / h3VCmK2L,暂时用不到,不需要登录 2、未授权…...

二叉树:填充每个节点的下一个右侧节点指针(java)

leetcode116:填充每个节点的下一个右侧节点指针 leetcode原题链接:题目描述递归解法一递归方法二(效率更高)二叉树专题 leetcode原题链接: 116题:填充每个节点的下一个右侧节点指针 题目描述 给定一个 完美二叉树 &a…...

Android 12.0修改系统默认设备类型的平板电脑类型为设备类型

1.概述 在12.0的系统rom产品开发中,对于产品设备类型都默认为tablet即平板电脑类型,即 product="tablet" 在一些不是平板的项目中,可能需要修改这个类型为device类型 即 product="device",这就需要找到相关设置系统属性的代码,修改系统属性就可以了 2…...

debug研究

debug研究 debug的condition 通常用在for循环里面 for循环中实际使用 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UsmJ93w5-1685344057464)(D:\typora_pic_all\image-20230529145417753.png)] log.info("当前共有{}条数据待处理", vos…...

zabbix监控系统

一、Zabbix概述 1、使用zabbix的原因 作为一个运维,需要会使用监控系统查看服务器状态以及网站流量指标,利用监控系统的数据去了解上线发布的结果,和网站的健康状态。 利用一个优秀的监控软件,我们可以: ●通过一个友好的界面进…...

Python入门学习

一、执行Python(Hello World)程序 对于大多数程序语言,第一个入门编程代码便是 “Hello World!”,以下代码为使用 Python 输出 “Hello World!” 1.1 创建hello.py文件 1.2 编写程序 #!/usr/bin/python…...

自动驾驶嵌入式开发工程师:车载SOC开发修炼秘籍

声明:本文档是博主在开发学习过程中写的笔记,本意是便于以后开发复盘,参考《 ug1144-petalinux-tools-reference-guide》、《ug1085》、黑金Zynq UltraScale MPSoC 5EV开发板资料、英伟达官方资料。大佬勿喷 大佬勿喷 大佬勿喷!&a…...

Linux之搭建环境

文章目录 1 FileZilla软件2 Linux搭建samba文件共享服务器,实现基于Linux和Windows的共享文件服务2.1 smaba的安装与基本应用2.2 samba的账号权限配置2.3 win系统下的文件无法复制到Linux共享文件夹中 1 FileZilla软件 在跟着正点原子教程安装后,出现如下…...

泡利矩阵(一)

〇、厄米矩阵 厄米矩阵(Hermitian Matrix),也称为自共轭矩阵(Self-adjoint Matrix),是线性代数中的一个重要概念。它是指一个复数域上的方阵,其转置矩阵与共轭矩阵相等。 具体来说&#xff0c…...

通用支付系统设计

支付永远是一个公司的核心领域,因为这是一个有交易属性公司的命脉。那么,支付系统到底长什么样,又是怎么运行交互的呢?抛开带有支付牌照的金融公司的支付架构,下述链路和系统组成基本上符合绝大多数支付场景。其实整体可以看成是…...

metaRTC+ZLMediaKit实现webrtc的推拉流

概述 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架,是一个支持webrtc SFU的优秀的流媒体服务器系统。 metaRTC新版本支持whip/whep协议,支持whip/whep协议的ZLMediaKit推拉流。 信令通信 ZLMediaKit新版本支持whip和whep协议,支…...

【JavaSE】Java基础语法(八)

文章目录 🍓1. 类和对象🍹🍹1.1 类和对象的关系🍹🍹1.2 类的定义 🍓2. 对象内存图🍹🍹2.1 单个对象内存图🍹🍹2.2 多个对象内存图2.3 多个对象指向相同内存图…...

Java如何配置环境变量

Java如何配置环境变量 0. 前言1. 下载Java2. 配置环境变量2.1新建 Java_Home2.2 编辑Path情况1情况2 3. 验证安装 0. 前言 本节记录如何配置Java环境变量,用自己重装过的系统实操 操作系统:Windows10 专业版 Java版本:jdk1.7.0_07 1. 下载…...

android 12.0SystemUI 状态栏下拉快捷添加截图快捷开关

1.概述 在12.0的系统产品rom定制化开发中,对SystemUI的定制需求也是挺多的,在下拉状态栏中 添加截图快捷开关,也是常有的开发功能,下面就以添加 截图功能为例功能的实现 2.SystemUI 状态栏下拉快捷添加截图快捷开关的核心代码 frameworks/base/packages/SystemUI/res/va…...

【无标题】 Vue 路由库Router 【重点】 - 安装 - 基本使用 - 路由配置 - 路由模式 - 路由传递参数 - 路由内置对象 - 路由守卫

0.0 课程介绍 Vue 路由库Router 【重点】 安装基本使用路由配置路由模式路由传递参数路由内置对象路由守卫 Vue的内置API 【掌握】 ref Vue.set Vue.nextTick Vue.filter Vue.component Vue.use Vue.directive 1.0 Vue的路由Router 【重点】 1.1 路由作用 进行页面…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​,覆盖应用全生命周期测试需求,主要提供五大核心能力: ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...