服务器测评网
我们一直在努力

Java如何优雅记录文章/商品浏览次数不重复?

在Java应用中记录浏览次数是一项常见的需求,广泛应用于文章阅读量、商品点击量、视频播放量等场景,实现这一功能需要考虑并发性能、数据一致性、存储效率等多个因素,本文将从数据库设计、缓存策略、并发控制、代码实现等方面详细介绍Java记录浏览次数的完整方案。

Java如何优雅记录文章/商品浏览次数不重复?

数据库设计基础

首先需要设计合理的数据库表结构来存储浏览数据,核心表应包含目标对象ID、浏览次数、统计时间等字段,可以创建一个view_count表,包含id(主键)、target_id(被浏览对象ID)、target_type(对象类型,如文章、商品等)、view_count(浏览次数)、created_at(创建时间)、updated_at(更新时间)等字段,这种设计支持多类型对象的浏览统计,通过target_type字段进行区分,对于高并发场景,建议在target_idtarget_type上建立联合索引,以提高查询效率。

缓存机制的应用

直接操作数据库在高并发场景下会成为性能瓶颈,因此引入缓存机制至关重要,Redis作为高性能的内存数据库,是记录浏览次数的理想选择,采用”缓存+数据库”的架构,先更新缓存再异步更新数据库,既能保证实时性,又能减轻数据库压力,具体实现时,可以使用Redis的INCR命令实现原子性递增操作,避免并发计数错误,当用户浏览某篇文章时,先执行redis.incr("article:view:" + articleId),然后通过定时任务或消息队列将缓存数据同步到数据库。

并发控制策略

在多线程环境下,浏览次数的统计必须保证线程安全,传统方案使用synchronized关键字或ReentrantLock,但这些方法在高并发时性能较差,基于Redis的原子操作是更优选择,因为INCR命令本身具有原子性,无需额外加锁,另一种方案是使用数据库的乐观锁,通过版本号控制并发更新,在更新view_count表时,添加version字段,执行UPDATE view_count SET view_count = view_count + 1, version = version + 1 WHERE id = ? AND version = ?,通过判断受影响行数确定更新是否成功。

具体代码实现

以下是使用Spring Boot和Redis实现浏览次数统计的核心代码,首先配置Redis连接,然后创建服务类处理浏览逻辑,在Controller层,当用户请求浏览内容时,调用服务方法:

Java如何优雅记录文章/商品浏览次数不重复?

@Service
public class ViewCountService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private ViewCountRepository viewCountRepository;
    private static final String VIEW_COUNT_KEY_PREFIX = "view:count:";
    public void incrementViewCount(String targetId, String targetType) {
        // 构建Redis键
        String redisKey = VIEW_COUNT_KEY_PREFIX + targetType + ":" + targetId;
        // 原子性递增缓存
        redisTemplate.opsForValue().increment(redisKey);
        // 设置过期时间,防止缓存无限增长
        redisTemplate.expire(redisKey, 1, TimeUnit.DAYS);
    }
    @Scheduled(fixedRate = 300000) // 每5分钟执行一次
    public void syncViewCountToDatabase() {
        // 获取所有相关缓存键
        Set<String> keys = redisTemplate.keys(VIEW_COUNT_KEY_PREFIX + "*");
        for (String key : keys) {
            String[] parts = key.split(":");
            String targetType = parts[2];
            String targetId = parts[3];
            Long count = Long.valueOf(redisTemplate.opsForValue().get(key).toString());
            // 更新数据库
            ViewCount viewCount = viewCountRepository.findByTargetIdAndTargetType(targetId, targetType)
                .orElse(new ViewCount(targetId, targetType, 0L));
            viewCount.setViewCount(viewCount.getViewCount() + count);
            viewCountRepository.save(viewCount);
            // 重置缓存
            redisTemplate.delete(key);
        }
    }
}

数据同步方案

缓存与数据库的数据一致性是关键问题,可以采用定时同步策略,如上述代码中每5分钟同步一次,平衡实时性与性能,对于实时性要求高的场景,可以采用消息队列(如RabbitMQ、Kafka)在每次缓存更新后发送同步消息,还可以结合数据库触发器,在数据变更时自动更新缓存,但这种方式会增加数据库负担。

性能优化技巧

为提升系统性能,可采取以下优化措施:1)使用Redis Pipeline批量处理缓存操作,减少网络开销;2)对热点数据采用本地缓存(如Caffeine)结合Redis二级缓存;3)分片存储,根据target_id的哈希值将数据分散到不同的Redis实例,避免单点压力;4)使用布隆过滤器快速判断用户是否已浏览,防止重复计数。

安全与防刷机制

为防止恶意刷量,需要加入安全防护,常见方案包括:1)基于用户ID或IP的限流,使用Redis的INCRBY命令和EXPIRE实现滑动窗口限流;2)验证码机制,对高频访问用户进行验证;3)用户行为分析,识别异常访问模式;4)设置合理的计数上限,如单用户单日最多计数10次。

监控与报警

建立完善的监控体系,确保浏览统计系统的稳定运行,可监控的关键指标包括:缓存命中率、数据库写入延迟、并发请求数量等,使用Prometheus+Grafana组合实现可视化监控,设置阈值报警,如当缓存命中率低于90%或数据库写入延迟超过100ms时触发报警。

Java如何优雅记录文章/商品浏览次数不重复?

通过以上方案,可以构建一个高性能、高可用的浏览次数统计系统,实际应用中,需要根据业务特点和并发量灵活选择技术方案,不断优化调整,以达到最佳效果。

赞(0)
未经允许不得转载:好主机测评网 » Java如何优雅记录文章/商品浏览次数不重复?