package model import ( "context" "database/sql" "fmt" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" "time" ) var _ UserProductsModel = (*customUserProductsModel)(nil) type UserProductItem struct { Id int64 `db:"id"` UserId int64 `db:"user_id"` ProductId int64 `db:"product_id"` ProductName string `db:"product_name"` ProductCode string `db:"product_code"` ProductDescription sql.NullString `db:"product_description"` ProductGroup string `db:"product_group"` ProductPrice float64 `db:"product_price"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` } type ( // UserProductsModel is an interface to be customized, add more methods here, // and implement the added methods in customUserProductsModel. UserProductsModel interface { userProductsModel FindUserProductsList(ctx context.Context, userId, page, pageSize int64) ([]*UserProductItem, int64, error) FindOneUserProduct(ctx context.Context, userId, productId int64) (*UserProducts, error) FindMatchUserProductCode(ctx context.Context, userId int64, productCode string) (bool, error) } customUserProductsModel struct { *defaultUserProductsModel rds *redis.Redis } ) // NewUserProductsModel returns a model for the database table. func NewUserProductsModel(rds *redis.Redis, conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) UserProductsModel { return &customUserProductsModel{ rds: rds, defaultUserProductsModel: newUserProductsModel(conn, c, opts...), } } func (m *defaultUserProductsModel) FindUserProductsList(ctx context.Context, userId, page, pageSize int64) ([]*UserProductItem, int64, error) { offset := (page - 1) * pageSize var userProducts []*UserProductItem // SQL查询语句,手动选择需要的products字段 query := ` SELECT up.id AS user_product_id, up.user_id, p.id AS product_id, p.product_name, p.product_code, COALESCE(p.product_description, '') AS product_description, p.product_group, p.product_price, up.created_at, up.updated_at FROM user_products up JOIN products p ON up.product_id = p.id WHERE up.user_id = ? ORDER BY up.created_at DESC LIMIT ?, ?` // 执行查询 err := m.QueryRowsNoCacheCtx(ctx, &userProducts, query, userId, offset, pageSize) if err != nil { return nil, 0, err } // 查询总数量 var total int64 countQuery := "SELECT COUNT(*) FROM user_products WHERE user_id = ?" err = m.QueryRowNoCacheCtx(ctx, &total, countQuery, userId) if err != nil { return nil, 0, err } return userProducts, total, nil } func (m *customUserProductsModel) FindOneUserProduct(ctx context.Context, userId, productId int64) (*UserProducts, error) { // 定义 Redis 缓存 Set 键 redisKey := fmt.Sprintf("user_products:%d", userId) // 检查 Redis Set 中是否存在用户与产品的关联 isMember, err := m.rds.SismemberCtx(ctx, redisKey, productId) if err == nil && isMember { // 如果 Redis Set 中存在,返回空,因为不需要重复查询 return nil, nil } var userProduct UserProducts query := fmt.Sprintf("SELECT %s FROM %s WHERE `user_id` = ? AND `product_id` = ? LIMIT 1", userProductsRows, m.table) err = m.QueryRowNoCacheCtx(ctx, &userProduct, query, userId, productId) switch err { case nil: // 将用户产品的关联写入 Redis Set _, err = m.rds.SaddCtx(ctx, redisKey, productId) if err != nil { return nil, err } return &userProduct, nil case sqlc.ErrNotFound: // 返回未找到的错误 return nil, ErrNotFound default: // 其他错误 return nil, err } } func (m *customUserProductsModel) FindMatchUserProductCode(ctx context.Context, userId int64, productCode string) (bool, error) { // 定义 Redis 缓存 Set 键 redisKey := fmt.Sprintf("user_products:%d", userId) // 1. 检查 Redis Set 中是否存在用户与产品的关联 isMember, err := m.rds.SismemberCtx(ctx, redisKey, productCode) if err == nil && isMember { // 如果 Redis Set 中存在,表示关联已存在,返回 true return true, nil } // 2. 如果 Redis 中没有匹配,则查询数据库 query := ` SELECT COUNT(*) FROM user_products up JOIN products p ON up.product_id = p.id WHERE up.user_id = ? AND p.product_code = ?` var count int err = m.QueryRowNoCacheCtx(ctx, &count, query, userId, productCode) if err != nil { // 如果数据库查询出错,返回错误 return false, err } // 3. 如果数据库查询成功且有记录,更新 Redis Set 并返回 true if count > 0 { _, redisErr := m.rds.SaddCtx(ctx, redisKey, productCode) if redisErr != nil { return false, redisErr // Redis 更新失败 } return true, nil } // 4. 如果没有找到匹配的关联,返回 false return false, nil }