github.com/go-board/x-go@v0.1.2-0.20220610024734-db1323f6cb15/xdatabase/xsql/cluster.go (about)

     1  package xsql
     2  
     3  import (
     4  	"database/sql"
     5  	"log"
     6  )
     7  
     8  type Cluster struct {
     9  	name     string
    10  	master   *sql.DB
    11  	slaves   []*sql.DB
    12  	selector Selector
    13  }
    14  
    15  func newDB(options ConnectionOptions) (*sql.DB, error) {
    16  	db, err := sql.Open(options.DriverName, options.Dsn)
    17  	if err != nil {
    18  		return nil, err
    19  	}
    20  	db.SetMaxIdleConns(options.MaxIdleConn)
    21  	db.SetMaxOpenConns(options.MaxOpenConn)
    22  	db.SetConnMaxLifetime(options.ConnMaxLifeTime)
    23  	return db, nil
    24  }
    25  
    26  // OpenCluster init new gorm client cluster with mysql database.
    27  // name is instance name of current mysql instance.
    28  // selector to select which slave node to use.
    29  // masterOption is master node options
    30  // slaveOptions are slave nodes options
    31  func OpenCluster(name string, selector Selector, masterOption ConnectionOptions, slaveOptions []ConnectionOptions) (*Cluster, error) {
    32  	if selector == nil {
    33  		selector = RoundRobinSelector()
    34  	}
    35  	db, err := newDB(masterOption)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	slaves := make([]*sql.DB, 0, len(slaveOptions))
    40  	for _, slaveCfg := range slaveOptions {
    41  		db, err := newDB(slaveCfg)
    42  		if err != nil {
    43  			// open connection to slave node failed, not affect the whole cluster state
    44  			log.Printf("[xdatabase/xsql] open slave node failed, driver_name(%s), dsn(%s), details(%+v\n)", slaveCfg.DriverName, slaveCfg.Dsn, err)
    45  			continue
    46  		}
    47  		slaves = append(slaves, db)
    48  	}
    49  	return &Cluster{
    50  		name:     name,
    51  		master:   db,
    52  		slaves:   slaves,
    53  		selector: selector,
    54  	}, nil
    55  }
    56  
    57  // Master return master node to do more operation.
    58  // 返回主节点。
    59  func (c *Cluster) Master() *sql.DB {
    60  	return c.master
    61  }
    62  
    63  // SlaveBySelector get slave db use user `Selector`.
    64  // 使用用户指定的选择器选择从节点。
    65  func (c *Cluster) SlaveBySelector(selector Selector) *sql.DB {
    66  	if len(c.slaves) == 0 {
    67  		return c.master
    68  	}
    69  	if len(c.slaves) == 1 {
    70  		return c.slaves[0]
    71  	}
    72  	return c.slaves[selector.SelectDB(len(c.slaves))]
    73  }
    74  
    75  // SlaveByKey get slave db use shard `Selector` with shard key.
    76  // 使用key来选择从节点。
    77  func (c *Cluster) SlaveByKey(key string) *sql.DB {
    78  	return c.SlaveBySelector(ShardSelector(key))
    79  }
    80  
    81  // Slave get slave db use default `Selector`.
    82  // 使用默认的选择器选择从节点。
    83  func (c *Cluster) Slave() *sql.DB {
    84  	return c.SlaveBySelector(c.selector)
    85  }
    86  
    87  // // Query will retrieve data slice from database, prefer to use slave node than master node.
    88  // // 从database 获取多条数据,优先从对应的从节点读取。
    89  // func (c *Cluster) Query(dest interface{}, sql string, args ...interface{}) error {
    90  // 	return c.Slave().Raw(sql, args...).Find(dest).Error
    91  // }
    92  
    93  // // QueryOne will retrieve one record from database, prefer to use slave node than master node.
    94  // // 从database 获取单条数据,优先从对应的从节点读取。
    95  // func (c *Cluster) QueryOne(dest interface{}, sql string, args ...interface{}) error {
    96  // 	return c.Slave().Raw(sql, args...).First(dest).Error
    97  // }
    98  
    99  // Exec will do update/insert/delete operation with master node.
   100  // 在主节点上执行 更新/插入/删除 操作。
   101  func (c *Cluster) Exec(sql string, args ...interface{}) error {
   102  	_, err := c.Master().Exec(sql, args...)
   103  	return err
   104  }
   105  
   106  // Run will do operation on master or slave node with user choose.
   107  // 用户可选的在何种节点上执行操作。
   108  func (c *Cluster) Run(fn func(master *sql.DB, slave *sql.DB) error) error {
   109  	return fn(c.Master(), c.Slave())
   110  }
   111  
   112  // Run will do operation on master or slave node with user choose, with key to select which slave node.
   113  // 用户可选的在何种节点上执行操作,key 用来选择从节点。
   114  func (c *Cluster) RunShard(key string, fn func(master *sql.DB, slave *sql.DB) error) error {
   115  	return fn(c.Master(), c.SlaveByKey(key))
   116  }
   117  
   118  // Transaction will do transaction on master node, with commit/rollback automatically.
   119  // 在主节点上执行事务,可以自动执行commit/rollback。
   120  func (c *Cluster) Transaction(fn func(tx *sql.Tx) error) error {
   121  	master := c.master
   122  	db, err := master.Begin()
   123  	if err != nil {
   124  		return err
   125  	}
   126  	if err := fn(db); err != nil {
   127  		_ = db.Rollback()
   128  		return err
   129  	}
   130  	return db.Commit()
   131  }