开始使用

配置

进入项目中的configs目录,mysql.toml,我们可以看到:

  1. [demo]
  2. addr = "127.0.0.1:3306"
  3. dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
  4. readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8","{user}:{password}@tcp(127.0.0.3:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
  5. active = 20
  6. idle = 10
  7. idleTimeout ="4h"
  8. queryTimeout = "200ms"
  9. execTimeout = "300ms"
  10. tranTimeout = "400ms"

在该配置文件中我们可以配置mysql的读和写的dsn、连接地址addr、连接池的闲置连接数idle、最大连接数active以及各类超时。

如果配置了readDSN,在进行读操作的时候会优先使用readDSN的连接。

初始化

进入项目的internal/dao目录,打开db.go,其中:

  1. var cfg struct {
  2. Client *sql.Config
  3. }
  4. checkErr(paladin.Get("db.toml").UnmarshalTOML(&dc))

使用paladin配置管理工具将上文中的db.toml中的配置解析为我们需要使用db的相关配置。

  1. // Dao dao.
  2. type Dao struct {
  3. db *sql.DB
  4. }

在dao的主结构提中定义了mysql的连接池对象。

  1. d = &dao{
  2. db: sql.NewMySQL(dc.Demo),
  3. }

使用kratos/pkg/database/sql包的NewMySQL方法进行连接池对象的初始化,需要传入上文解析的配置。

Ping

  1. // Ping ping the resource.
  2. func (d *dao) Ping(ctx context.Context) (err error) {
  3. return d.db.Ping(ctx)
  4. }

生成的dao层模板中自带了mysql相关的ping方法,用于为负载均衡服务的健康监测提供依据,详见blademaster

关闭

  1. // Close close the resource.
  2. func (d *dao) Close() {
  3. d.db.Close()
  4. }

在关闭dao层时,通过调用mysql连接池对象的Close方法,我们可以关闭该连接池,从而释放相关资源。

常用方法

单个查询

  1. // GetDemo 用户角色
  2. func (d *dao) GetDemo(c context.Context, did int64) (demo int8, err error) {
  3. err = d.db.QueryRow(c, _getDemoSQL, did).Scan(&demo)
  4. if err != nil && err != sql.ErrNoRows {
  5. log.Error("d.GetDemo.Query error(%v)", err)
  6. return
  7. }
  8. return demo, nil
  9. }

db.QueryRow方法用于返回最多一条记录的查询,在QueryRow方法后使用Scan方法即可将mysql的返回值转换为Golang的数据类型。

当mysql查询不到对应数据时,会返回sql.ErrNoRows,如果不需处理,可以参考如上代码忽略此error。

批量查询

  1. // ResourceLogs ResourceLogs.
  2. func (d *dao) GetDemos(c context.Context, dids []int64) (demos []int8, err error) {
  3. rows, err := d.db.Query(c, _getDemosSQL, dids)
  4. if err != nil {
  5. log.Error("query error(%v)", err)
  6. return
  7. }
  8. defer rows.Close()
  9. for rows.Next() {
  10. var tmpD int8
  11. if err = rows.Scan(&tmpD); err != nil {
  12. log.Error("scan demo log error(%v)", err)
  13. return
  14. }
  15. demos = append(demos, tmpD)
  16. }
  17. return
  18. }

db.Query方法一般用于批量查询的场景,返回*sql.Rows和error信息。 我们可以使用rows.Next()方法获得下一行的返回结果,并且配合使用rows.Scan()方法将该结果转换为Golang的数据类型。当没有下一行时,rows.Next方法将返回false,此时循环结束。

注意,在使用完毕rows对象后,需要调用rows.Close方法关闭连接,释放相关资源。

执行语句

  1. // DemoExec exec
  2. func (d *Dao) DemoExec(c context.Context, id int64) (rows int64, err error) {
  3. res, err := d.db.Exec(c, _demoUpdateSQL, id)
  4. if err != nil {
  5. log.Error("db.DemoExec.Exec(%s) error(%v)", _demoUpdateSQL, err)
  6. return
  7. }
  8. return res.RowsAffected()
  9. }

执行UPDATE/DELETE/INSERT语句时,使用db.Exec方法进行语句执行,返回*sql.Result和error信息:

  1. // A Result summarizes an executed SQL command.
  2. type Result interface {
  3. LastInsertId() (int64, error)
  4. RowsAffected() (int64, error)
  5. }

Result接口支持获取影响行数和LastInsertId(一般用于获取Insert语句插入数据库后的主键ID)

事务

kratos/pkg/database/sql包支持事务操作,具体操作示例如下:

开启一个事务:

  1. tx := d.db.Begin()
  2. if err = tx.Error; err != nil {
  3. log.Error("db begin transcation failed, err=%+v", err)
  4. return
  5. }

在事务中执行语句:

  1. res, err := tx.Exec(_demoSQL, did)
  2. if err != nil {
  3. return
  4. }
  5. rows := res.RowsAffected()

提交事务:

  1. if err = tx.Commit().Error; err!=nil{
  2. log.Error("db commit transcation failed, err=%+v", err)
  3. }

回滚事务:

  1. if err = tx.Rollback().Error; err!=nil{
  2. log.Error("db rollback failed, err=%+v", rollbackErr)
  3. }

扩展阅读