这篇主要学习go项目中的项目结构、项目规范等知识,ROM采用的database/sql的写法。

1.技术框架

利用的是ginweb框架,然后ROM层选用database/sql,安装mysql驱动。安装方式如下:

//使用github上的gin托管地址
$ go get -u github.com/gin-gonic/gin
$ go get github.com/go-sql-driver/mysql

2.项目结构如下

项目结构分析:

  • 1、main.go主要是存放路由,启动项目;
  • 2、router主要存放路由信息,然后返回一个router
  • 3、apis存放routerHandler函数;
  • 4、databases存放数据连接信息;
  • 5、models存放数据模型,类似Java中POJO对象。
│  main.go

├─.idea
│ │ go.iml
│ │ misc.xml
│ │ modules.xml
│ │ workspace.xml
│ │
│ └─inspectionProfiles
├─apis
│ person.go

├─databases
│ mysql.go

├─models
│ person.go

└─router
router.go
image.png

3.main.go代码解释

package main
import (
//这里讲db作为go/databases的一个别名,表示数据库连接池
db "go/databases"
. "go/router"
)
func main() {
//当整个程序完成之后关闭数据库连接
defer db.SqlDB.Close()
router := InitRouter()
router.Run(":8080")
}

4.router.go代码解释

package router
import (
"github.com/gin-gonic/gin"
."go/apis"
)
func InitRouter() *gin.Engine {
router := gin.Default()
//IndexApi为一个Handler
router.GET("/", IndexApi)
router.POST("/person", AddPersonApi)
router.GET("/persons", GetPersonsApi)
router.GET("/person/:id", GetPersonApi)
router.PUT("/person/:id", ModPersonApi)
router.DELETE("/person/:id", DelPersonApi)
return router
}

5.mysql.go代码解释

package databases
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"log"
)
//因为我们需要在其他地方使用SqlDB这个变量,所以需要大写代表public
var SqlDB *sql.DB
//初始化方法
func init() {
var err error
SqlDB, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?parseTime=true")
if err != nil {
log.Fatal(err.Error())
}
//连接检测
err = SqlDB.Ping()
if err != nil {
log.Fatal(err.Error())
}
}

使用sql.Open()方法会创建一个数据库连接池db。这个地步不是数据库连接,它是一个连接池,只有当真正的数据库通信的时候才创建连接。例如,这里的db.Ping()操作。db.SetMaxIdleConns(20)db.SetMaxOpenConns(20)分别设置数据库的空闲连接和最大打开连接,即向Mysql服务端发出的所有连接的最大数目。

6.models中person.go代码解释

package models
import (
"log"
db "go/databases"
)
//定义person类型结构
type Person struct {
Id int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
} func (p *Person) AddPerson() (id int64, err error) {
rs, err := db.SqlDB.Exec("INSERT INTO person(first_name, last_name) VALUES (?, ?)", p.FirstName, p.LastName)
if err != nil {
return
}
id, err = rs.LastInsertId()
return
} func (p *Person) GetPersons() (persons []Person, err error) {
persons = make([]Person, 0)
rows, err := db.SqlDB.Query("SELECT id, first_name, last_name FROM person")
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
var person Person
rows.Scan(&person.Id, &person.FirstName, &person.LastName)
persons = append(persons, person)
}
if err = rows.Err(); err != nil {
return
}
return
} func (p *Person) GetPerson() (person Person, err error) {
err = db.SqlDB.QueryRow("SELECT id, first_name, last_name FROM person WHERE id=?", p.Id).Scan(
&person.Id, &person.FirstName, &person.LastName,
)
return
} func (p *Person) ModPerson() (ra int64, err error) {
stmt, err := db.SqlDB.Prepare("UPDATE person SET first_name=?, last_name=? WHERE id=?")
defer stmt.Close()
if err != nil {
return
}
rs, err := stmt.Exec(p.FirstName, p.LastName, p.Id)
if err != nil {
return
}
ra, err = rs.RowsAffected()
return
} func (p *Person) DelPerson() (ra int64, err error) {
rs, err := db.SqlDB.Exec("DELETE FROM person WHERE id=?", p.Id)
if err != nil {
log.Fatalln(err)
}
ra, err = rs.RowsAffected()
return
}

执行非query操作,使用dbExec方法,在MySQL中使用做占位符。最后我们把插入后的Id返回给客户端。

GetPersons方法解释:

读取MySQL的数据需要有一个绑定的过程,db.Query()方法返回一个rows对象,这个数据库连接随即转移到这个对象,因此我们需要定义rows.Close()操作,然后创建一个[]Person的切片。

使用make,而不是直接使用var persons []Person的声明方式。还是有所差别的,使用make的方式,当数组切片没有元素的时候,Json会返回[]。如果直接声明,json会返回null

接下来就是使用rows对象的Next()方法,遍历所查询的数据,一个个绑定到person对象上,最后appendperson切片。

7.apis中的person.go代码解释

package apis

import (
"net/http"
"log"
"fmt"
"strconv"
"github.com/gin-gonic/gin"
."go/models"
) func IndexApi(c *gin.Context) {
c.String(http.StatusOK, "It works")
} func AddPersonApi(c *gin.Context) {
firstName := c.Request.FormValue("first_name")
lastName := c.Request.FormValue("last_name") p := Person{FirstName: firstName, LastName: lastName} ra, err := p.AddPerson()
if err != nil {
log.Fatalln(err)
}
msg := fmt.Sprintf("insert successful %d", ra)
c.JSON(http.StatusOK, gin.H{
"msg": msg,
})
} func GetPersonsApi(c *gin.Context) {
var p Person
persons, err := p.GetPersons()
if err != nil {
log.Fatalln(err)
} c.JSON(http.StatusOK, gin.H{
"persons": persons,
}) } func GetPersonApi(c *gin.Context) {
cid := c.Param("id")
id, err := strconv.Atoi(cid)
if err != nil {
log.Fatalln(err)
}
p := Person{Id: id}
person, err := p.GetPerson()
if err != nil {
log.Fatalln(err)
} c.JSON(http.StatusOK, gin.H{
"person": person,
}) } func ModPersonApi(c *gin.Context) {
cid := c.Param("id")
id, err := strconv.Atoi(cid)
if err != nil {
log.Fatalln(err)
}
p := Person{Id: id}
err = c.Bind(&p)
if err != nil {
log.Fatalln(err)
}
ra, err := p.ModPerson()
if err != nil {
log.Fatalln(err)
}
msg := fmt.Sprintf("Update person %d successful %d", p.Id, ra)
c.JSON(http.StatusOK, gin.H{
"msg": msg,
})
} func DelPersonApi(c *gin.Context) {
cid := c.Param("id")
id, err := strconv.Atoi(cid)
if err != nil {
log.Fatalln(err)
}
p := Person{Id: id}
ra, err := p.DelPerson()
if err != nil {
log.Fatalln(err)
}
msg := fmt.Sprintf("Delete person %d successful %d", id, ra)
c.JSON(http.StatusOK, gin.H{
"msg": msg,
})
}

其实,整个项目的结构和CRUD操作跟Java中的思想比较类似,应该很容易上手。需要注意一点的是,如果需要将整个项目运行起来,项目的路径一定Gopath路径:F:\Go\Project\src;

image.png
image.png

项目启动结果如下:

image.png

熟悉了database/sql的写法后,下一步就是学习ROM框架gorm的写法,进而学习Docker进行部署。

最新文章

  1. 用ProGet搭建内部的NuGet服务器
  2. Python 【第六章】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy
  3. 解决在iOS8环境下,当用户关闭定位服务总开关时,无法将APP定位子选项加入定位权限列表的问题
  4. VC6.0读取Excel文件数据
  5. systemtap-与 oracle 转
  6. objective-c中使用cocoa的NSPredicate,谓词(十四)
  7. How to interact with the Chef Server using the Chef Server API using Shell script
  8. 结构体 typedef关键字
  9. Activity---Fragment---listView的实现
  10. tomcat解析之简单web服务器(图)
  11. Python---day5-各类模块的使用
  12. css的单位
  13. C# 根据路径删除文件或文件夹
  14. yii2自带的backend,frontend不够用,添加一个后台模块怎么做?
  15. Swift3的playground中对UI直接测试支持的改变
  16. python运行js
  17. 获取APP的元素信息和Activity
  18. Shell常见问题整理
  19. vmware workstation 14 快速安装操作系统
  20. python各种模块,迭代器,生成器

热门文章

  1. SQL中join连接查询时条件放在on后与where后的区别
  2. Java计算工作日的工具类
  3. 啊哈!算法(第一章)C#实现
  4. python3 根据时间获取本月一号和月末日期
  5. 『正睿OI 2019SC Day3』
  6. 可落地的DDD(3)-如何利用DDD进行微服务的划分
  7. Linux学习笔记之iptables学习笔记
  8. java中反射知识点总结
  9. 面对代码中过多的if...else的解决方法
  10. WebApi自定义全局异常过滤器及返回数据格式化