All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neko233.skilltree.game.redDot.impl.RedDotTreeByMysql Maven / Gradle / Ivy

There is a newer version: 0.3.6
Show newest version
package com.neko233.skilltree.game.redDot.impl;

import com.neko233.skilltree.commons.core.utils.*;
import com.neko233.skilltree.commons.sql.SqlTemplate233;
import com.neko233.skilltree.game.redDot.RedDotTree;
import com.neko233.skilltree.game.redDot.dto.RedDotDto;
import com.neko233.skilltree.game.redDot.dto.RedPointRemoveResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 红点树 by mysql
 */
@Slf4j
public class RedDotTreeByMysql implements RedDotTree {

    public static final String CREATE_TABLE_IF_NOT_EXISTS =
            "create table if not exists red_point_tree " +
                    "                    ( " +
                    "                        id       bigint primary key auto_increment, " +
                    "                        userId   varchar(128) comment '用户id', " +
                    "                        path     varchar(512) comment '路径. 根节点为 /', " +
                    "                        count    long comment '数量', " +
                    "                        expireMs bigint comment '过期毫秒时间戳', " +
                    "                        createDt datetime default now() comment '创建时间', " +
                    "                        unique key uk_user_redPoint(userId, path) " +
                    "                    );" ;
    public static final String UPSERT_SQL = StringUtils233.trimIdent("insert into red_point_tree(userId, path, count, expireMs) " +
            "            Values (${userId}, ${path}, ${count}, ${expireMs}) " +
            "            on duplicate key update count = values(count), expireMs = values(expireMs)"
    );


    // db
    private final DataSource dataSource;
    // 直接接入
    private final RedDotTreeByMemory redDotTreeByMemory;
    // 用户 id
    private final String userId;


    public static RedDotTreeByMysql create(Number userId, DataSource dataSource) {
        if (userId == null) {
            throw new IllegalArgumentException("userId can not null!");
        }
        return create(String.valueOf(userId), dataSource);
    }

    public static RedDotTreeByMysql create(String userId, DataSource dataSource) {
        if (StringUtils.isBlank(userId)) {
            throw new IllegalArgumentException("userId can not blank ! ");
        }
        return new RedDotTreeByMysql(userId, dataSource);
    }


    private RedDotTreeByMysql(String userId, DataSource dataSource) {
        this.dataSource = dataSource;
        this.userId = userId;

        try (Connection c = dataSource.getConnection()) {
            PreparedStatement ps = c.prepareStatement(CREATE_TABLE_IF_NOT_EXISTS);
            ps.executeUpdate();
        } catch (Exception e) {
            log.error("[RedPo] create table error! create SQL = {}", CREATE_TABLE_IF_NOT_EXISTS, e);
            // create table error
        }

        String selectSql = KvTemplate233.builder("Select * From red_point_tree Where userId = ${userId}")
                .put("userId", String.valueOf(userId))
                .build();

        try (Connection c = dataSource.getConnection();
             PreparedStatement ps = c.prepareStatement(selectSql)) {

            ResultSet rs = ps.executeQuery();

            LinkedList redDotDtoList = new LinkedList<>();
            while (rs.next()) {
                redDotDtoList.add(RedDotDto.createByDbQuery(rs));
            }
            this.redDotTreeByMemory = RedDotTreeByMemory.from(redDotDtoList);
        } catch (Exception e) {
            throw new RuntimeException("init error", e);
        } finally {

        }
    }


    /**
     * Insert, Update, Delete
     */
    @Override
    public void flush(List toUpdatePathList) {
        List redPointList = null;
        if (CollectionUtils233.isEmpty(toUpdatePathList)) {
            redPointList = this.getAllRedDotList();
        } else {
            redPointList = toUpdatePathList.stream()
                    .map(redDotTreeByMemory::getRedDot)
                    .collect(Collectors.toList());
        }

        try (Connection c = dataSource.getConnection()) {
            // delete
            if (CollectionUtils.isEmpty(redPointList)) {
                this.deleteAllMyData(c);
                return;
            }

            // upsert
            upsert(redPointList, c);
        } catch (Exception e) {
            throw new RuntimeException("[RedDotTree] 红点 upsert error", e);
        }
    }

    private void deleteAllMyData(Connection c) throws SQLException {
        String deleteSql = SqlTemplate233.builder("Delete From red_point_tree Where userId = ${userId} ")
                .put("userId", userId)
                .build();

        PreparedStatement ps = c.prepareStatement(deleteSql);
        log.debug("userId = {} clear all redPoint Data. Delete SQL = {}", userId, deleteSql);
        ps.execute();
    }

    private void upsert(List redPointList, Connection c) throws SQLException {
        List uspertSqlList = redPointList.stream()
                .map(data -> SqlTemplate233.builder(UPSERT_SQL)
                        .put("userId", userId)
                        .put("path", data.getPath())
                        .put("count", data.getCount())
                        .put("expireMs", data.getExpireMs())
                        .build())
                .collect(Collectors.toList());


        // 挺搞的
        PreparedStatement ps = null;
        for (String sql : uspertSqlList) {
            log.debug("[RedDotTree] upsert 红点. sql = {}", sql);
            ps = c.prepareStatement(sql);
            ps.execute();
        }

        CloseableUtils233.close(ps);
    }

    @Override
    public void clear() {
        this.redDotTreeByMemory.clear();

        flush();
    }

    @Nullable
    @Override
    public Long getExpireMsByPath(String path) {
        return this.redDotTreeByMemory.getExpireMsByPath(path);
    }

    @Override
    @Nullable
    public RedDotDto getByRefresh(String path) {
        RedDotDto byRefresh = this.redDotTreeByMemory.getByRefresh(path);
        if (byRefresh == null) {
            flush(ListUtils233.of(path));
        }
        return byRefresh;
    }

    @Override
    public List getAllChildPathList(String path) {
        return this.redDotTreeByMemory.getAllChildPathList(path);
    }

    @Override
    public List getAllParentPathList(String path) {
        return this.redDotTreeByMemory.getAllParentPathList(path);
    }

    @Override
    public boolean isExpire(String path) {
        return this.redDotTreeByMemory.isExpire(path);
    }

    @Override
    public Map getPathToValueMap() {
        return this.redDotTreeByMemory.getPathToValueMap();
    }

    @Override
    @Nullable
    public RedPointRemoveResult removeRedDot(String path) {
        RedPointRemoveResult result = this.redDotTreeByMemory.removeRedDot(path);
        if (result == null) {
            return null;
        }

        List toRemovePathList = result.getRemoveChildPathList();

        this.deleteMysqlDataByPath(toRemovePathList);

        return result;
    }

    /**
     * 删除 mysql 数据
     *
     * @param toRemovePathList 要移除的路径
     */
    private void deleteMysqlDataByPath(List toRemovePathList) {
        List deleteSqlList = toRemovePathList.stream()
                .map(path -> SqlTemplate233.builder("Delete From red_point_tree Where userId = ${userId} and path = ${path} ")
                        .put("userId", userId)
                        .put("path", path)
                        .build())
                .collect(Collectors.toList());

        try (Connection c = dataSource.getConnection()) {
            for (String s : deleteSqlList) {
                PreparedStatement ps = c.prepareStatement(s);
                ps.execute();
            }
        } catch (Exception e) {
            throw new RuntimeException("delete error", e);
        }

    }

    @Override
    public List addRedDot(String path, int value, long expireTimeMs) {
        List toUpdatePathList = this.redDotTreeByMemory.addRedDot(path, value, expireTimeMs);

        flush(toUpdatePathList);

        return toUpdatePathList;
    }

    @Override
    public List updateRedDotValue(String path, long value) {
        List toUpdatePathList = this.redDotTreeByMemory.updateRedDotValue(path, value);

        flush(toUpdatePathList);

        return toUpdatePathList;
    }


    @Override
    public Map getAllDataMap(Collection filterPathList) {
        return this.redDotTreeByMemory.getAllDataMap(filterPathList);
    }

    @Override
    public Map getAllDataMap() {
        return this.redDotTreeByMemory.getAllDataMap();
    }

    @Override
    public RedDotDto getRedDot(String path) {
        return this.redDotTreeByMemory.getRedDot(path);
    }

    @Override
    public long getRedDotValue(String path) {
        return this.redDotTreeByMemory.getRedDotValue(path);
    }

    @Override
    public List getAllRedDotList() {
        return this.redDotTreeByMemory.getAllRedDotList();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy