(1). 单服务器:
①. topic服务负责CURD、权限等.其业务比较复杂、压力不大.
②. 单台服务器,为了业务可以适当的采用ORM等成熟框架提高业务开发速度.
③. 为了增加可维护性,适当的牺牲一些性能.
④. 业务级服务.
(2). 多台服务器:
①. 访问压力大,两台负载均衡只负责获取帖子的业务(只负责展示),适合不用框架.
②. 另外一台压力不大,只负责操作帖子(CUD)、权限等.
③. 微服务领域的api接口.
①. mysql驱动:
https://github.com/go-sql-driver/mysql
②. gorm:
https://github.com/jinzhu/gorm
③. 安装:
$ go get -u github.com/go-sql-driver/mysql
$ go get -u github.com/jinzhu/gorm
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
db, _ := gorm.Open("mysql", "root:@tcp(127.0.0.1:3306)/gongci?charset=utf8&parseTime=True&loc=Local")
(1). 原生sql:
rows, _ := db.Raw("select id, class_name from topic_class").Rows()
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
fmt.Println(id, name)
}
defer db.Close()
(2). gorm:
// 创建一个struct进行模型映射
type TopicClass struct {
Id int
ClassName string
// 理论上映射为class_type,但是字段是classtype,可用于历史项目
ClassType string `gorm:"Column:classtype"`
}
type Topic struct {
TopicId int `json:"id" gorm:"PRIMARY_KEY;Column:id"` // json反射的映射字段
TopicTitle string `json:"title" binding:"required"`
TopicUrl string `json:"url" binding:"omitempty,topicurl" gorm:"Column:topicurl"`
}
// 显示日志
db.LogMode(true)
// 单条的TopicClass struct实例化
topic := &TopicClass{}
db.First(&topic, 1) // Table 'test.topic_classes' doesn't exist
fmt.Println(topic) // &{1 新闻}
// 多条定义一个切片
var topics []src.TopicClass
db.Find(&topics)
fmt.Println(topics) // SELECT * FROM `topic_classes` [{1 新闻 } {2 话题 }]
// 插入数据
insert := src.Topic{
TopicTitle: "PHP",
TopicUrl: "phpurl",
}
fmt.Println(db.Create(&insert).RowsAffected) // 1
// INSERT INTO `topics` (`topic_title`,`topicurl`) VALUES ('PHP','phpurl')
fmt.Println(insert.TopicId) // 3
defer db.Close()
注:
①. 表名规则:
根据struct名称改成小写,并且加上复数形式,如struct名为:
a. Test,对应表名为tests
b. TopicClass表名为topic_classes(注意复数,ch sh x s结尾时加es就复数)
②. db.SingularTable(true)让gorm转义struct名字的时候不用加上s.
③. 强制指定表名,历史项目,表名已经固定:
db.Table("test").First(&test)
④. 字段规则:
a. 对于字段TopicId对应的字段就是topic_id
⑤. First传第二个参数表示是主键是多少,且是数字类型的:
db.First(&topic, 1)
SELECT * FROM `topic_classes` WHERE (`topic_classes`.`id` = 1) ORDER BY `topic_classes`.`id` ASC LIMIT 1
⑥. 带条件语句:
db.Table("test").Where("class_name=?", "新闻").First(&test)
或
db.Table("test").Where(&TopicClass{ClassName: "新闻"}).First(&test)
(1). api.test.com/topic/main.go:
import "topic.test.com/src"
func main() {
router := gin.Default()
v1 := router.Group("/v1/topics")
v1.GET("/:topic_id", src.GetDetail)
router.Run()
}
(2). api.test.com/topic/src/TopicDao.go:
func GetDetail (c *gin.Context) {
// 不是用query参数了,因为这个不是?后面的参数,是/v1/topic/:topic_id最后一个变量
id := c.Param("topic_id")
topic := &Topic{}
DBHelper.First(&topic, id)
c.JSON(200, topic)
defer DBHelper.Close() // 退出数据库连接
}
(3). api.test.com/topic/src/TopicModel.go:
type Topic struct {
TopicId int `json:"id" gorm:"PRIMARY_KEY;Column:id"` // json反射的映射字段
TopicTitle string `json:"title" binding:"required"`
TopicUrl string `json:"url" binding:"omitempty,topicurl" gorm:"Column:topicurl"`
}
(4). api.test.com/topic/src/DB.go:
var DBHelper *gorm.DB
var err error
func init () {
DBHelper, err = gorm.Open("mysql", "root:@tcp(127.0.0.1:3306)/gongci?charset=utf8&parseTime=True&loc=Local")
if err != nil {
fmt.Println("数据库连接失败")
}
DBHelper.LogMode(true)
}
(5).问题点:
当第一次访问能返回数据,再次访问时,返回一个空的struct对象:
{"id": 0, "title": "", "url": ""}
日志并提示database is closed
SHOW PROCESSLIST
Id User Host DB Command Time state Info
2 root localhost:58517 gongci Query 0 starting SHOW PROCESSLIST
3 root localhost:58569 gongci Sleep 277
5 root localhost:58873 gongci Sleep 160
db.DB()可以返回原生的sql.db这个对象
db.DB().SetMaxIdleConns(number)
db.DB().SetMaxOpenConns(100)
db.DB().SetConnMaxLifetime(time.Hour)
// DB get *sql.DB
from current connection
// If the underlying database connection is not a *sql.DB, returns nil
func (s *DB) DB() *sql.DB {
db, _ := s.db.(*sql.DB)
return db
}