Files
tyapi-server/examples/modern_cached_user_repository.go
2025-07-20 20:53:26 +08:00

456 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package examples
import (
"context"
"time"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/domains/user/entities"
"tyapi-server/internal/domains/user/repositories"
"tyapi-server/internal/domains/user/repositories/queries"
"tyapi-server/internal/shared/database"
"tyapi-server/internal/shared/interfaces"
)
// ModernCachedUserRepository 现代化的用户仓储(使用新缓存方案)
type ModernCachedUserRepository struct {
*database.CachedBaseRepositoryImpl
}
// 编译时检查接口实现
var _ repositories.UserRepository = (*ModernCachedUserRepository)(nil)
// NewModernCachedUserRepository 创建现代化缓存用户仓储
func NewModernCachedUserRepository(db *gorm.DB, logger *zap.Logger) repositories.UserRepository {
return &ModernCachedUserRepository{
CachedBaseRepositoryImpl: database.NewCachedBaseRepositoryImpl(db, logger, "users"),
}
}
// ================ Repository[T] 接口实现 ================
// Create 创建用户(自动失效相关缓存)
func (r *ModernCachedUserRepository) Create(ctx context.Context, user entities.User) (entities.User, error) {
r.GetLogger().Info("创建用户", zap.String("phone", user.Phone))
// 使用基础创建方法GORM插件会自动处理缓存失效
err := r.CreateEntity(ctx, &user)
return user, err
}
// GetByID 根据ID获取用户自动缓存30分钟
func (r *ModernCachedUserRepository) GetByID(ctx context.Context, id string) (entities.User, error) {
var user entities.User
// 使用智能缓存查询自动缓存30分钟
err := r.SmartGetByID(ctx, id, &user)
return user, err
}
// Update 更新用户(自动失效相关缓存)
func (r *ModernCachedUserRepository) Update(ctx context.Context, user entities.User) error {
r.GetLogger().Info("更新用户", zap.String("user_id", user.ID))
// 使用基础更新方法GORM插件会自动处理缓存失效
return r.UpdateEntity(ctx, &user)
}
// CreateBatch 批量创建用户
func (r *ModernCachedUserRepository) CreateBatch(ctx context.Context, users []entities.User) error {
r.GetLogger().Info("批量创建用户", zap.Int("count", len(users)))
return r.CreateBatchEntity(ctx, &users)
}
// GetByIDs 根据ID列表获取用户带缓存
func (r *ModernCachedUserRepository) GetByIDs(ctx context.Context, ids []string) ([]entities.User, error) {
var users []entities.User
// 使用批量缓存查询缓存15分钟
err := r.BatchGetWithCache(ctx, ids, &users, 15*time.Minute)
return users, err
}
// UpdateBatch 批量更新用户
func (r *ModernCachedUserRepository) UpdateBatch(ctx context.Context, users []entities.User) error {
r.GetLogger().Info("批量更新用户", zap.Int("count", len(users)))
return r.UpdateBatchEntity(ctx, &users)
}
// DeleteBatch 批量删除用户
func (r *ModernCachedUserRepository) DeleteBatch(ctx context.Context, ids []string) error {
r.GetLogger().Info("批量删除用户", zap.Strings("ids", ids))
return r.DeleteBatchEntity(ctx, ids, &entities.User{})
}
// List 获取用户列表(智能缓存)
func (r *ModernCachedUserRepository) List(ctx context.Context, options interfaces.ListOptions) ([]entities.User, error) {
var users []entities.User
// 使用智能列表查询,根据查询复杂度自动选择缓存策略
err := r.SmartList(ctx, &users, options)
return users, err
}
// ================ BaseRepository 接口实现 ================
// Delete 删除用户
func (r *ModernCachedUserRepository) Delete(ctx context.Context, id string) error {
return r.DeleteEntity(ctx, id, &entities.User{})
}
// Exists 检查用户是否存在(带缓存)
func (r *ModernCachedUserRepository) Exists(ctx context.Context, id string) (bool, error) {
return r.ExistsEntity(ctx, id, &entities.User{})
}
// Count 统计用户数量(智能缓存)
func (r *ModernCachedUserRepository) Count(ctx context.Context, options interfaces.CountOptions) (int64, error) {
var count int64
// 计算缓存TTL
cacheTTL := 10 * time.Minute
if options.Search != "" {
cacheTTL = 2 * time.Minute // 搜索查询缓存时间更短
}
err := r.CountWithCache(ctx, &count, cacheTTL, &entities.User{}, "", nil)
return count, err
}
// SoftDelete 软删除用户
func (r *ModernCachedUserRepository) SoftDelete(ctx context.Context, id string) error {
return r.SoftDeleteEntity(ctx, id, &entities.User{})
}
// Restore 恢复用户
func (r *ModernCachedUserRepository) Restore(ctx context.Context, id string) error {
return r.RestoreEntity(ctx, id, &entities.User{})
}
// ================ 业务专用方法使用新缓存API ================
// GetByPhone 根据手机号获取用户缓存15分钟
func (r *ModernCachedUserRepository) GetByPhone(ctx context.Context, phone string) (*entities.User, error) {
var user entities.User
// 使用智能字段查询自动缓存15分钟
err := r.SmartGetByField(ctx, &user, "phone", phone, 15*time.Minute)
if err != nil {
return nil, err
}
return &user, nil
}
// GetByUsername 根据用户名获取用户缓存15分钟
func (r *ModernCachedUserRepository) GetByUsername(ctx context.Context, username string) (*entities.User, error) {
var user entities.User
err := r.SmartGetByField(ctx, &user, "username", username, 15*time.Minute)
if err != nil {
return nil, err
}
return &user, nil
}
// GetByUserType 根据用户类型获取用户列表
func (r *ModernCachedUserRepository) GetByUserType(ctx context.Context, userType string) ([]*entities.User, error) {
var users []*entities.User
err := r.FindWithCache(ctx, &users, 30*time.Minute, "user_type = ?", userType)
return users, err
}
// ListUsers 获取用户列表(带分页和筛选)
func (r *ModernCachedUserRepository) ListUsers(ctx context.Context, query *queries.ListUsersQuery) ([]*entities.User, int64, error) {
var users []*entities.User
var total int64
// 构建查询条件
db := r.GetDB(ctx).Set("cache:enabled", true).Set("cache:ttl", 15*time.Minute)
// 应用筛选条件
if query.Phone != "" {
db = db.Where("phone LIKE ?", "%"+query.Phone+"%")
}
if query.StartDate != "" {
db = db.Where("created_at >= ?", query.StartDate)
}
if query.EndDate != "" {
db = db.Where("created_at <= ?", query.EndDate)
}
// 统计总数
if err := db.Model(&entities.User{}).Count(&total).Error; err != nil {
return nil, 0, err
}
// 应用分页
offset := (query.Page - 1) * query.PageSize
if err := db.Offset(offset).Limit(query.PageSize).Find(&users).Error; err != nil {
return nil, 0, err
}
return users, total, nil
}
// ValidateUser 验证用户登录
func (r *ModernCachedUserRepository) ValidateUser(ctx context.Context, phone, password string) (*entities.User, error) {
// 登录验证不使用缓存,确保安全性
var user entities.User
db := r.WithoutCache().GetDB(ctx)
err := db.Where("phone = ? AND password = ?", phone, password).First(&user).Error
if err != nil {
return nil, err
}
return &user, nil
}
// UpdateLastLogin 更新最后登录时间
func (r *ModernCachedUserRepository) UpdateLastLogin(ctx context.Context, userID string) error {
now := time.Now()
return r.GetDB(ctx).Model(&entities.User{}).
Where("id = ?", userID).
Updates(map[string]interface{}{
"last_login_at": &now,
"updated_at": now,
}).Error
}
// UpdatePassword 更新密码
func (r *ModernCachedUserRepository) UpdatePassword(ctx context.Context, userID string, newPassword string) error {
return r.GetDB(ctx).Model(&entities.User{}).
Where("id = ?", userID).
Update("password", newPassword).Error
}
// CheckPassword 检查密码
func (r *ModernCachedUserRepository) CheckPassword(ctx context.Context, userID string, password string) (bool, error) {
var count int64
err := r.GetDB(ctx).Model(&entities.User{}).
Where("id = ? AND password = ?", userID, password).
Count(&count).Error
return count > 0, err
}
// ActivateUser 激活用户
func (r *ModernCachedUserRepository) ActivateUser(ctx context.Context, userID string) error {
return r.GetDB(ctx).Model(&entities.User{}).
Where("id = ?", userID).
Update("active", true).Error
}
// DeactivateUser 停用用户
func (r *ModernCachedUserRepository) DeactivateUser(ctx context.Context, userID string) error {
return r.GetDB(ctx).Model(&entities.User{}).
Where("id = ?", userID).
Update("active", false).Error
}
// UpdateLoginStats 更新登录统计
func (r *ModernCachedUserRepository) UpdateLoginStats(ctx context.Context, userID string) error {
return r.GetDB(ctx).Model(&entities.User{}).
Where("id = ?", userID).
Updates(map[string]interface{}{
"login_count": gorm.Expr("login_count + 1"),
"last_login_at": time.Now(),
}).Error
}
// GetStats 获取用户统计信息
func (r *ModernCachedUserRepository) GetStats(ctx context.Context) (*repositories.UserStats, error) {
var stats repositories.UserStats
// 使用短期缓存获取统计信息
db := r.GetDB(ctx).Set("cache:enabled", true).Set("cache:ttl", 5*time.Minute)
// 总用户数
if err := db.Model(&entities.User{}).Count(&stats.TotalUsers).Error; err != nil {
return nil, err
}
// 活跃用户数
if err := db.Model(&entities.User{}).Where("active = ?", true).Count(&stats.ActiveUsers).Error; err != nil {
return nil, err
}
// 今日注册数
today := time.Now().Truncate(24 * time.Hour)
if err := db.Model(&entities.User{}).Where("created_at >= ?", today).Count(&stats.TodayRegistrations).Error; err != nil {
return nil, err
}
// 今日登录数
if err := db.Model(&entities.User{}).Where("last_login_at >= ?", today).Count(&stats.TodayLogins).Error; err != nil {
return nil, err
}
return &stats, nil
}
// GetStatsByDateRange 获取指定日期范围的用户统计
func (r *ModernCachedUserRepository) GetStatsByDateRange(ctx context.Context, startDate, endDate string) (*repositories.UserStats, error) {
var stats repositories.UserStats
db := r.GetDB(ctx).Set("cache:enabled", true).Set("cache:ttl", 10*time.Minute)
// 指定时间范围内的注册数
if err := db.Model(&entities.User{}).
Where("created_at >= ? AND created_at <= ?", startDate, endDate).
Count(&stats.TodayRegistrations).Error; err != nil {
return nil, err
}
// 指定时间范围内的登录数
if err := db.Model(&entities.User{}).
Where("last_login_at >= ? AND last_login_at <= ?", startDate, endDate).
Count(&stats.TodayLogins).Error; err != nil {
return nil, err
}
return &stats, nil
}
// GetActiveUsers 获取活跃用户(使用短期缓存)
func (r *ModernCachedUserRepository) GetActiveUsers(ctx context.Context) ([]entities.User, error) {
var users []entities.User
// 活跃用户查询使用短期缓存5分钟
err := r.WithShortCache().FindWithCache(ctx, &users, 5*time.Minute, "active = ?", true)
return users, err
}
// GetUsersByType 根据用户类型获取用户(使用中期缓存)
func (r *ModernCachedUserRepository) GetUsersByType(ctx context.Context, userType string) ([]entities.User, error) {
var users []entities.User
// 用户类型查询使用中期缓存30分钟
err := r.WithMediumCache().FindWithCache(ctx, &users, 30*time.Minute, "user_type = ?", userType)
return users, err
}
// GetRecentUsers 获取最近注册用户(禁用缓存,实时数据)
func (r *ModernCachedUserRepository) GetRecentUsers(ctx context.Context, limit int) ([]entities.User, error) {
var users []entities.User
// 最近用户查询禁用缓存,保证数据实时性
db := r.WithoutCache().GetDB(ctx)
err := db.Order("created_at DESC").Limit(limit).Find(&users).Error
return users, err
}
// GetPopularUsers 获取热门用户(使用长期缓存)
func (r *ModernCachedUserRepository) GetPopularUsers(ctx context.Context, limit int) ([]entities.User, error) {
var users []entities.User
// 热门用户查询使用长期缓存2小时
err := r.WithLongCache().GetDB(ctx).
Order("login_count DESC").
Limit(limit).
Find(&users).Error
return users, err
}
// SearchUsers 搜索用户(智能缓存策略)
func (r *ModernCachedUserRepository) SearchUsers(ctx context.Context, keyword string, limit int) ([]entities.User, error) {
var users []entities.User
// 搜索查询使用短期缓存,避免频繁的数据库查询
db := r.GetDB(ctx).
Set("cache:enabled", true).
Set("cache:ttl", 2*time.Minute). // 搜索结果缓存2分钟
Where("username LIKE ? OR phone LIKE ?", "%"+keyword+"%", "%"+keyword+"%").
Limit(limit)
err := db.Find(&users).Error
return users, err
}
// ================ 缓存管理方法 ================
// WarmupUserCache 预热用户缓存
func (r *ModernCachedUserRepository) WarmupUserCache(ctx context.Context) error {
r.GetLogger().Info("开始预热用户缓存")
// 定义预热查询
queries := []database.WarmupQuery{
{
Name: "active_users",
TTL: 30 * time.Minute,
Dest: &[]entities.User{},
},
{
Name: "user_types",
TTL: 60 * time.Minute,
Dest: &[]entities.User{},
},
{
Name: "recent_users",
TTL: 10 * time.Minute,
Dest: &[]entities.User{},
},
}
return r.WarmupCommonQueries(ctx, queries)
}
// RefreshUserCache 刷新用户缓存
func (r *ModernCachedUserRepository) RefreshUserCache(ctx context.Context) error {
r.GetLogger().Info("刷新用户缓存")
// 刷新用户相关的所有缓存
return r.RefreshCache(ctx, "users:*")
}
// GetUserCacheStats 获取用户缓存统计
func (r *ModernCachedUserRepository) GetUserCacheStats() map[string]interface{} {
stats := r.GetCacheInfo()
stats["specific_patterns"] = []string{
"gorm_cache:users:*",
"user:id:*",
"user:phone:*",
}
return stats
}
// ================ 使用示例 ================
// ExampleUsage 使用示例
func (r *ModernCachedUserRepository) ExampleUsage(ctx context.Context) {
// 1. 基础查询(自动缓存)
user, _ := r.GetByID(ctx, "user-123")
r.GetLogger().Info("获取用户", zap.String("username", user.Username))
// 2. 手动控制缓存
// 使用短期缓存查询
var activeUsers []entities.User
_ = r.WithShortCache().FindWithCache(ctx, &activeUsers, 5*time.Minute, "active = ?", true)
r.GetLogger().Info("活跃用户数", zap.Int("count", len(activeUsers)))
// 禁用缓存查询
var recentUsers []entities.User
_ = r.WithoutCache().FindWhere(ctx, &recentUsers, "created_at > ?", time.Now().AddDate(0, 0, -7))
r.GetLogger().Info("最近用户数", zap.Int("count", len(recentUsers)))
// 3. 智能缓存查询
options := interfaces.ListOptions{
Page: 1,
PageSize: 20,
Filters: map[string]interface{}{"active": true},
Sort: "created_at",
Order: "desc",
}
users, _ := r.List(ctx, options) // 自动根据查询复杂度选择缓存策略
r.GetLogger().Info("用户列表", zap.Int("count", len(users)))
// 4. 缓存预热
r.WarmupUserCache(ctx)
}