go从0到1项目实战体系二十三:GORM

1. 哪些场景下适合ORM?

(1). 单服务器:
     ①. topic服务负责CURD、权限等.其业务比较复杂、压力不大.
     ②. 单台服务器,为了业务可以适当的采用ORM等成熟框架提高业务开发速度.
     ③. 为了增加可维护性,适当的牺牲一些性能.
     ④. 业务级服务.

(2). 多台服务器:
     ①. 访问压力大,两台负载均衡只负责获取帖子的业务(只负责展示),适合不用框架.
	 ②. 另外一台压力不大,只负责操作帖子(CUD)、权限等.
     ③. 微服务领域的api接口.

4.2 go的gorm:

①. 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

4.3 CURD:

_ "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)

4.4 返回一条数据:

(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
}

你可能感兴趣的:(go语言,golang,驱动开发,开发语言)