mysql.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package vip
  2. import (
  3. "context"
  4. "crypto/md5"
  5. "database/sql"
  6. "encoding/hex"
  7. "fmt"
  8. "strconv"
  9. "time"
  10. "go-common/app/service/live/xuser/model"
  11. "go-common/library/log"
  12. xtime "go-common/library/time"
  13. "github.com/pkg/errors"
  14. xsql "go-common/library/database/sql"
  15. )
  16. const (
  17. _userVipRecordPrefix = "user_vip_record_%d"
  18. _userVipRecordCount = 10
  19. _userLevelPrefix = "user_"
  20. )
  21. var (
  22. errUpdateVipTimeInvalid = errors.New("update vip but vip_time invalid")
  23. )
  24. var (
  25. // get vip info from user_x table
  26. _getVipInfo = "SELECT `vip`,`vip_time`,`svip`,`svip_time` FROM `%s` WHERE uid=?;"
  27. // insert into user_vip_record_n
  28. _insertUserVipRecord = "INSERT INTO `%s` (`uid`,`vip_type`,`vip_num`,`order_id`,`platform`,`source`) VALUES (?,?,?,?,?,?);"
  29. // update user_vip_record_n before_time & status after update vip success
  30. _updateUserVipRecordStatus = "UPDATE `%s` SET `before_vip`=?,`before_vip_time`=?,`before_svip`=?,`before_svip_time`=?,`status`=? WHERE `id`=?;"
  31. // update user_x vip info
  32. _updateAllVip = "UPDATE `%s` SET `vip`=?,`vip_time`=?,`svip`=?,`svip_time`=? WHERE uid=?;"
  33. _updateVip = "UPDATE `%s` SET `vip`=?,`vip_time`=? WHERE uid=?;"
  34. // insert vip
  35. _insertVip = "INSERT INTO `%s` (`uid`,`vip`,`vip_time`,`svip`,`svip_time`) VALUES (?,?,?,?,?);"
  36. // delete vip
  37. _deleteVip = "DELETE FROM `%s` WHERE `uid`=? LIMIT 1;"
  38. // insert ap_vip_record
  39. _insertApVipRecord = "INSERT INTO `ap_vip_record`(`uid`,`type`,`vip_time`,`platform`) VALUES (?,?,?,?);"
  40. )
  41. // GetVipFromDB get vip info by uid
  42. // return error maybe sql no row or just scan error, how to handle decided by upper business
  43. func (d *Dao) GetVipFromDB(ctx context.Context, uid int64) (info *model.VipInfo, err error) {
  44. var (
  45. vipTime, sVipTime xtime.Time
  46. currentTime = xtime.Time(time.Now().Unix())
  47. )
  48. row := d.db.QueryRow(ctx, fmt.Sprintf(_getVipInfo, getUserLevelTable(uid)), uid)
  49. info = &model.VipInfo{}
  50. if err = row.Scan(&info.Vip, &vipTime, &info.Svip, &sVipTime); err != nil {
  51. log.Error("[dao.vip.mysql|GetVipFromDB] row scan error(%v), uid(%d)", err, uid)
  52. // no rows in user_x table, async insert one, don't return error
  53. if err == xsql.ErrNoRows {
  54. go d.createVip(context.TODO(), uid, info)
  55. err = nil
  56. return
  57. }
  58. return
  59. }
  60. // format info vip time
  61. if vipTime <= 0 {
  62. info.VipTime = model.TimeEmpty
  63. } else {
  64. info.VipTime = vipTime.Time().Format(model.TimeNano)
  65. }
  66. if sVipTime <= 0 {
  67. info.SvipTime = model.TimeEmpty
  68. } else {
  69. info.SvipTime = sVipTime.Time().Format(model.TimeNano)
  70. }
  71. // format vip & svip
  72. // 注意!!! db里的数据不一定正确,可能含有已经过期的time
  73. if vipTime <= currentTime {
  74. info.Vip = 0
  75. }
  76. if sVipTime <= currentTime {
  77. info.Svip = 0
  78. }
  79. return
  80. }
  81. // AddVip update user_n vip fields, add vip/svip time
  82. // weather add vip or svip, vipTime should not be empty
  83. func (d *Dao) AddVip(ctx context.Context, uid int64, vipTime, sVipTime xtime.Time) (row int64, err error) {
  84. var (
  85. vt, st string
  86. res sql.Result
  87. updateType string
  88. currentTime = xtime.Time(time.Now().Unix())
  89. )
  90. if vipTime <= currentTime {
  91. return 0, errUpdateVipTimeInvalid
  92. }
  93. vt = vipTime.Time().Format(model.TimeNano)
  94. if sVipTime > currentTime {
  95. // update vip and svip
  96. st = sVipTime.Time().Format(model.TimeNano)
  97. updateType = "all"
  98. res, err = d.db.Exec(ctx, fmt.Sprintf(_updateAllVip, getUserLevelTable(uid)), 1, vt, 1, st, uid)
  99. } else {
  100. // update vip only
  101. updateType = "vip"
  102. res, err = d.db.Exec(ctx, fmt.Sprintf(_updateVip, getUserLevelTable(uid)), 1, vt, uid)
  103. }
  104. if err != nil {
  105. log.Error("[dao.vip.mysql|AddVip] update vip error(%v), type(%s), uid(%d), vip(%s), svip(%s)",
  106. err, updateType, uid, vt, st)
  107. return
  108. }
  109. row, _ = res.RowsAffected()
  110. return
  111. }
  112. // createVip create user_n vip row, for internal usage only. Do not use in business!
  113. func (d *Dao) createVip(ctx context.Context, uid int64, info *model.VipInfo) (err error) {
  114. info = d.initInfo(info)
  115. log.Info("[dao.vip.mysql|createVip] create user_n row, uid(%d), info(%v)", uid, info)
  116. _, err = d.db.Exec(ctx, fmt.Sprintf(_insertVip, getUserLevelTable(uid)),
  117. uid, info.Vip, info.VipTime, info.Svip, info.SvipTime)
  118. if err != nil {
  119. log.Error("[dao.vip.mysql|createVip] create error(%v), uid(%d), info(%v)", err, uid, info)
  120. }
  121. return
  122. }
  123. // deleteVip delete user_n vip row, for internal usage only. Do not use in business!
  124. func (d *Dao) deleteVip(ctx context.Context, uid int64) (err error) {
  125. log.Info("[dao.vip.mysql|deleteVip] delete user_n row, uid(%d)", uid)
  126. _, err = d.db.Exec(ctx, fmt.Sprintf(_deleteVip, getUserLevelTable(uid)), uid)
  127. if err != nil {
  128. log.Error("[dao.vip.mysql|deleteVip] delete error(%v), uid(%d)", err, uid)
  129. }
  130. return
  131. }
  132. // CreateVipRecord create user vip record if not exists
  133. // return error maybe unique key exists err or other db error, upper business should notice
  134. // unique key is (uid,order_id)
  135. func (d *Dao) CreateVipRecord(ctx context.Context, req *model.VipBuy) (recordID int64, err error) {
  136. res, err := d.db.Exec(ctx, fmt.Sprintf(_insertUserVipRecord, getUserVipRecordTable(req.Uid)),
  137. req.Uid, req.GoodID, req.GoodNum, req.OrderID, req.Platform, req.Source)
  138. if err != nil {
  139. log.Error("[dao.vip.mysql|CreateUserVipRecord] create user vip record error(%v), req(%v)", err, req)
  140. return
  141. }
  142. if recordID, err = res.LastInsertId(); err != nil {
  143. err = errors.WithStack(err)
  144. log.Error("[dao.vip.mysql|CreateUserVipRecord] get last insert id error(%v), req(%v)", err, req)
  145. }
  146. return
  147. }
  148. // UpdateVipRecord update user vip record after buy success
  149. func (d *Dao) UpdateVipRecord(ctx context.Context, recordID, uid int64, info *model.VipInfo) (err error) {
  150. execSql := fmt.Sprintf(_updateUserVipRecordStatus, getUserVipRecordTable(uid))
  151. _, err = d.db.Exec(ctx, execSql, info.Vip, info.VipTime, info.Svip, info.SvipTime, model.BuyStatusSuccess, recordID)
  152. if err != nil {
  153. log.Error("[dao.vip.mysql|UpdateVipRecordLater] update error(%v), record id(%d), uid(%d), info(%v)",
  154. err, recordID, uid, info)
  155. }
  156. return
  157. }
  158. // CreateApVipRecord create ap_vip_record
  159. func (d *Dao) CreateApVipRecord(ctx context.Context, record *model.VipRecord) (row int64, err error) {
  160. res, err := d.db.Exec(ctx, _insertApVipRecord, record.Uid, record.VipType, record.AfterVipTime, record.Platform)
  161. if err != nil {
  162. log.Error("[dao.vip.mysql|CreateApVipRecord] insert ap_vip_record error(%v), record(%v)", err, record)
  163. return
  164. }
  165. row, _ = res.RowsAffected()
  166. return
  167. }
  168. // getUserLevelTable get user_x table by uid
  169. func getUserLevelTable(uid int64) string {
  170. uidStr := strconv.FormatInt(uid, 10)
  171. md5Ctx := md5.New()
  172. md5Ctx.Write([]byte(uidStr))
  173. cipher := md5Ctx.Sum(nil)
  174. return _userLevelPrefix + hex.EncodeToString(cipher)[0:1]
  175. }
  176. // getUserVipRecordTable get user_vip_record_x table by uid
  177. func getUserVipRecordTable(uid int64) string {
  178. return fmt.Sprintf(_userVipRecordPrefix, uid%_userVipRecordCount)
  179. }