skyalcon 發表於 2026-2-1 12:50

ClanRecommendTable

package com.lineage.server.datatables.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.lineage.DatabaseFactory;
import com.lineage.server.datatables.CharObjidTable;
import com.lineage.server.datatables.lock.ClanReading;
import com.lineage.server.datatables.storage.ClanRecommendStorage;
import com.lineage.server.templates.L1ClanRecommend;
import com.lineage.server.utils.PerformanceTimer;

/**
* 血盟推薦登錄表
* 修正重點:
* 1. 使用 Try-with-resources 自動關閉資源 (解決 Resource Leak 警告)。
* 2. 移除 SQLUtil.close 的冗餘呼叫。
* 3. 修正 deleteIllegalData 中連續執行 SQL 的資源管理。
*/
public final class ClanRecommendTable implements ClanRecommendStorage {

        private static final Log _log = LogFactory.getLog(ClanRecommendTable.class);

        private final Map<Integer, L1ClanRecommend> _recommendsList = new ConcurrentHashMap<>();

        private final Map<Integer, CopyOnWriteArrayList<Integer>> _applyList = new ConcurrentHashMap<>();

        @Override
        public final void load() {
                final PerformanceTimer timer = new PerformanceTimer();
                deleteIllegalData();

                // 第一部分:載入推薦名單
                try (Connection con = DatabaseFactory.get().getConnection();
                       PreparedStatement pstm = con.prepareStatement("SELECT * FROM clan_recommend ORDER BY clan_id");
                       ResultSet rs = pstm.executeQuery()) {

                        while (rs.next()) {
                                final int clan_id = rs.getInt("clan_id");

                                if (ClanReading.get().getTemplate(clan_id) == null) {
                                        deleteRecommend(clan_id);
                                        continue;
                                }

                                final int type_id = rs.getInt("type_id");
                                final String type_message = rs.getString("type_message");
                               
                                if ((type_message == null) || type_message.isEmpty()) {
                                        deleteRecommend(clan_id);
                                        continue;
                                }

                                final L1ClanRecommend recommend = new L1ClanRecommend(clan_id, type_id, type_message);
                                _recommendsList.put(clan_id, recommend);
                        }
                } catch (final SQLException e) {
                        _log.error("載入推薦名單失敗", e);
                }

                // 第二部分:載入申請名單 (分開 try 確保資源獨立)
                try (Connection con = DatabaseFactory.get().getConnection();
                       PreparedStatement pstm = con.prepareStatement("SELECT * FROM clan_request_list ORDER BY clan_id");
                       ResultSet rs = pstm.executeQuery()) {

                        while (rs.next()) {
                                final int clan_id = rs.getInt("clan_id");
                                final int applicant_id = rs.getInt("applicant_id");

                                if ((ClanReading.get().getTemplate(clan_id) == null)
                                                || (CharObjidTable.get().isChar(applicant_id) == null)) {
                                        deleteRecommendApply(clan_id, applicant_id);
                                        continue;
                                }

                                CopyOnWriteArrayList<Integer> total_list = _applyList.computeIfAbsent(clan_id, k -> new CopyOnWriteArrayList<>());
                                total_list.add(applicant_id);
                        }

                } catch (final SQLException e) {
                        _log.error("載入申請名單失敗", e);
                }
               
                _log.info("載入血盟推薦登錄資料數量: " + _recommendsList.size() + "(" + timer.get() + "ms)");
        }

        private final void deleteIllegalData() {
                try (Connection con = DatabaseFactory.get().getConnection()) {
                        // 刪除無效的推薦
                        try (PreparedStatement pstm = con.prepareStatement(
                                        "DELETE FROM clan_recommend WHERE clan_id NOT IN(SELECT clan_id FROM clan_data) || up_time < DATE_SUB(CURDATE(), INTERVAL 3 DAY)")) {
                                pstm.execute();
                        }
                        // 刪除無效的申請
                        try (PreparedStatement pstm = con.prepareStatement(
                                        "DELETE FROM clan_request_list WHERE clan_id NOT IN(SELECT clan_id FROM clan_data) || clan_id NOT IN(SELECT clan_id FROM clan_recommend)")) {
                                pstm.execute();
                        }
                } catch (final SQLException e) {
                        _log.error("清理非法推薦數據失敗", e);
                }
        }

        @Override
        public final void insertRecommend(final int clan_id, final String clan_name, final String leader_name,
                        final int type_id, final String type_message) {
                if (_recommendsList.containsKey(clan_id)) {
                        return;
                }

                try (Connection con = DatabaseFactory.get().getConnection();
                       PreparedStatement pstm = con.prepareStatement(
                                        "INSERT INTO clan_recommend SET clan_id=?, clan_name=?, leader_name=?, type_id=?, type_message=?, up_time=SYSDATE()")) {
                       
                        pstm.setInt(1, clan_id);
                        pstm.setString(2, clan_name);
                        pstm.setString(3, leader_name);
                        pstm.setInt(4, type_id);
                        pstm.setString(5, type_message);
                        pstm.execute();

                        _recommendsList.put(clan_id, new L1ClanRecommend(clan_id, type_id, type_message));

                } catch (final SQLException e) {
                        _log.error("新增推薦失敗", e);
                }
        }

        @Override
        public final void insertRecommendApply(final int clan_id, final String clan_name, final int applicant_id,
                        final String applicant_name) {
               
                CopyOnWriteArrayList<Integer> total_list = _applyList.computeIfAbsent(clan_id, k -> new CopyOnWriteArrayList<>());
                if (total_list.contains(applicant_id)) {
                        return;
                }

                try (Connection con = DatabaseFactory.get().getConnection();
                       PreparedStatement pstm = con.prepareStatement(
                                        "INSERT INTO clan_request_list SET clan_id=?, clan_name=?, applicant_id=?, applicant_name=?")) {
                       
                        pstm.setInt(1, clan_id);
                        pstm.setString(2, clan_name);
                        pstm.setInt(3, applicant_id);
                        pstm.setString(4, applicant_name);
                        pstm.execute();

                        total_list.add(applicant_id);

                } catch (final SQLException e) {
                        _log.error("新增申請失敗", e);
                }
        }

        @Override
        public final void updateRecommend(final int clan_id, final int type_id, final String type_message) {
                try (Connection con = DatabaseFactory.get().getConnection();
                       PreparedStatement pstm = con.prepareStatement(
                                        "UPDATE clan_recommend SET type_id=?, type_message=?, up_time=SYSDATE() WHERE clan_id=?")) {
                       
                        pstm.setInt(1, type_id);
                        pstm.setString(2, type_message);
                        pstm.setInt(3, clan_id);
                        pstm.execute();

                        L1ClanRecommend recommend = _recommendsList.get(clan_id);
                        if (recommend != null) {
                                recommend.setTypeId(type_id);
                                recommend.setTypeMessage(type_message);
                        }

                } catch (final SQLException e) {
                        _log.error("更新推薦失敗", e);
                }
        }

        @Override
        public final void deleteRecommend(final int clan_id) {
                try (Connection con = DatabaseFactory.get().getConnection();
                       PreparedStatement pstm = con.prepareStatement("DELETE FROM clan_recommend WHERE clan_id=?")) {
                       
                        pstm.setInt(1, clan_id);
                        pstm.execute();

                        _recommendsList.remove(clan_id);

                } catch (final SQLException e) {
                        _log.error("刪除推薦失敗", e);
                }
        }

        @Override
        public final void deleteRecommendApply(final int chan_id, final int char_id) {
                // 記憶體清理
                if (chan_id != 0) {
                        final CopyOnWriteArrayList<Integer> list = _applyList.get(chan_id);
                        if (list != null && list.remove(Integer.valueOf(char_id))) {
                                if (list.isEmpty()) {
                                        _applyList.remove(chan_id);
                                }
                        }
                } else {
                        _applyList.values().removeIf(list -> {
                                list.remove(Integer.valueOf(char_id));
                                return list.isEmpty();
                        });
                }

                // 資料庫清理
                String sql = "DELETE FROM clan_request_list WHERE applicant_id=?";
                if (chan_id != 0) {
                        sql += " AND clan_id=?";
                }

                try (Connection con = DatabaseFactory.get().getConnection();
                       PreparedStatement pstm = con.prepareStatement(sql)) {
                       
                        pstm.setInt(1, char_id);
                        if (chan_id != 0) {
                                pstm.setInt(2, chan_id);
                        }
                        pstm.execute();

                } catch (final SQLException e) {
                        _log.error("刪除申請失敗", e);
                }
        }

        @Override
        public final Map<Integer, L1ClanRecommend> getRecommendsList() {
                return _recommendsList;
        }

        @Override
        public final Map<Integer, CopyOnWriteArrayList<Integer>> getApplyList() {
                return _applyList;
        }
}

fdbggeca 發表於 2026-2-2 19:04

搖搖搖搖搖搖搖搖搖搖
頁: [1]
查看完整版本: ClanRecommendTable