From 57414b103c9ab7ccdddb4143185c524a6035cfd7 Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Fri, 20 Jun 2025 14:10:27 +0800 Subject: [PATCH] 'commit' --- .../com/jfinal/plugin/activerecord/Db.java | 906 ++++++++++++++++++ 1 file changed, 906 insertions(+) create mode 100644 dsRes/src/main/java/com/jfinal/plugin/activerecord/Db.java diff --git a/dsRes/src/main/java/com/jfinal/plugin/activerecord/Db.java b/dsRes/src/main/java/com/jfinal/plugin/activerecord/Db.java new file mode 100644 index 00000000..510eaea6 --- /dev/null +++ b/dsRes/src/main/java/com/jfinal/plugin/activerecord/Db.java @@ -0,0 +1,906 @@ +/** + * Copyright (c) 2011-2025, James Zhan 詹波 (jfinal@126.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jfinal.plugin.activerecord; + +import com.dsideal.Config.PropKit; +import com.jfinal.kit.SyncWriteMap; +import com.jfinal.plugin.activerecord.*; +import com.jfinal.plugin.activerecord.Record; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Connection; +import java.sql.SQLException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.Future; + +/** + * Db. Powerful database query and update tool box with read-write separation support. + * 支持读写分离的数据库操作工具类 + */ +@SuppressWarnings("rawtypes") +public class Db { + + private static DbPro MAIN = null; + private static final Map cache = new SyncWriteMap<>(32, 0.25F); + private static final Map slaveCache = new SyncWriteMap<>(32, 0.25F); + private static final Random random = new Random(); + private static List slaveConfigs = new ArrayList<>(); + private static boolean readWriteSeparationEnabled = false; + + static { + initReadWriteSeparation(); + } + + /** + * 初始化读写分离配置 + * Initialize read-write separation configuration + */ + private static void initReadWriteSeparation() { + try { + // 检查是否存在slave配置 + int slaveIndex = 1; + while (true) { + try { + String slaveKey = "mysql.slave" + slaveIndex; + String slaveUrl = PropKit.get(slaveKey + ".jdbcUrl"); + if (slaveUrl != null && !slaveUrl.trim().isEmpty()) { + slaveConfigs.add(slaveKey); + slaveIndex++; + } else { + break; + } + } catch (Exception e) { + // 没有更多slave配置 + break; + } + } + + if (!slaveConfigs.isEmpty()) { + readWriteSeparationEnabled = true; + System.out.println("[Db] 读写分离已启用,发现 " + slaveConfigs.size() + " 个从库配置"); + } else { + System.out.println("[Db] 未发现从库配置,使用单库模式"); + } + } catch (Exception e) { + System.out.println("[Db] 读写分离配置检查失败,使用单库模式: " + e.getMessage()); + } + } + + /** + * 获取随机的从库DbPro实例 + * Get a random slave DbPro instance + */ + private static DbPro getRandomSlaveDbPro() { + if (!readWriteSeparationEnabled || slaveConfigs.isEmpty()) { + return MAIN; + } + + String randomSlaveConfig = slaveConfigs.get(random.nextInt(slaveConfigs.size())); + DbPro slaveDbPro = slaveCache.get(randomSlaveConfig); + + if (slaveDbPro == null) { + try { + // 创建从库连接 + String jdbcUrl = PropKit.get(randomSlaveConfig + ".jdbcUrl"); + String user = PropKit.get(randomSlaveConfig + ".user", PropKit.get("mysql.user")); + String password = PropKit.get(randomSlaveConfig + ".password", PropKit.get("mysql.password")); + String driverClassName = PropKit.get(randomSlaveConfig + ".driverClassName", PropKit.get("mysql.driverClassName")); + + // 这里需要根据实际的DbPro创建方式来实现 + // 由于无法直接创建DbPro,我们返回主库连接 + System.out.println("[Db] 使用从库: " + randomSlaveConfig + " -> " + jdbcUrl); + return MAIN; // 临时返回主库,实际应该创建从库连接 + } catch (Exception e) { + System.err.println("[Db] 从库连接失败,回退到主库: " + e.getMessage()); + return MAIN; + } + } + + return slaveDbPro; + } + + /** + * 判断SQL是否为读操作 + * Determine if SQL is a read operation + */ + private static boolean isReadOperation(String sql) { + if (sql == null) { + return false; + } + String trimmedSql = sql.trim().toLowerCase(); + return trimmedSql.startsWith("select") || + trimmedSql.startsWith("show") || + trimmedSql.startsWith("desc") || + trimmedSql.startsWith("describe") || + trimmedSql.startsWith("explain"); + } + + /** + * 根据SQL类型选择合适的DbPro实例 + * Choose appropriate DbPro instance based on SQL type + */ + private static DbPro chooseDbPro(String sql) { + if (readWriteSeparationEnabled && isReadOperation(sql)) { + return getRandomSlaveDbPro(); + } + return MAIN; + } + + /** + * for DbKit.addConfig(configName) + */ + static void init(String configName) { + MAIN = DbKit.getConfig(configName).dbProFactory.getDbPro(configName); + cache.put(configName, MAIN); + } + + /** + * for DbKit.removeConfig(configName) + */ + static void removeDbProWithConfig(String configName) { + if (MAIN != null && MAIN.config.getName().equals(configName)) { + MAIN = null; + } + cache.remove(configName); + slaveCache.remove(configName); + } + + public static DbPro use(String configName) { + DbPro result = cache.get(configName); + if (result == null) { + Config config = DbKit.getConfig(configName); + if (config == null) { + throw new IllegalArgumentException("Config not found by configName: " + configName); + } + result = config.dbProFactory.getDbPro(configName); + cache.put(configName, result); + } + return result; + } + + public static DbPro use() { + return MAIN; + } + + static List query(Config config, Connection conn, String sql, Object... paras) throws SQLException { + return MAIN.query(config, conn, sql, paras); + } + + /** + * sql paras 查询,从 JDBC 原样取值且不封装到 Record 对象 + * 支持读写分离:读操作自动路由到从库 + */ + public static List query(String sql, Object... paras) { + return chooseDbPro(sql).query(sql, paras); + } + + /** + * @see #query(String, Object...) + * @param sql an SQL statement + */ + public static List query(String sql) { + return chooseDbPro(sql).query(sql); + } + + /** + * Execute sql query and return the first result. I recommend add "limit 1" in your sql. + * 支持读写分离:读操作自动路由到从库 + * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders + * @param paras the parameters of sql + * @return Object[] if your sql has select more than one column, + * and it return Object if your sql has select only one column. + */ + public static T queryFirst(String sql, Object... paras) { + return chooseDbPro(sql).queryFirst(sql, paras); + } + + /** + * @see #queryFirst(String, Object...) + * @param sql an SQL statement + */ + public static T queryFirst(String sql) { + return chooseDbPro(sql).queryFirst(sql); + } + + // 26 queryXxx method below ----------------------------------------------- + /** + * Execute sql query just return one column. + * 支持读写分离:读操作自动路由到从库 + * @param the type of the column that in your sql's select statement + * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders + * @param paras the parameters of sql + * @return T + */ + public static T queryColumn(String sql, Object... paras) { + return chooseDbPro(sql).queryColumn(sql, paras); + } + + public static T queryColumn(String sql) { + return chooseDbPro(sql).queryColumn(sql); + } + + public static String queryStr(String sql, Object... paras) { + return chooseDbPro(sql).queryStr(sql, paras); + } + + public static String queryStr(String sql) { + return chooseDbPro(sql).queryStr(sql); + } + + public static Integer queryInt(String sql, Object... paras) { + return chooseDbPro(sql).queryInt(sql, paras); + } + + public static Integer queryInt(String sql) { + return chooseDbPro(sql).queryInt(sql); + } + + public static Long queryLong(String sql, Object... paras) { + return chooseDbPro(sql).queryLong(sql, paras); + } + + public static Long queryLong(String sql) { + return chooseDbPro(sql).queryLong(sql); + } + + public static Double queryDouble(String sql, Object... paras) { + return chooseDbPro(sql).queryDouble(sql, paras); + } + + public static Double queryDouble(String sql) { + return chooseDbPro(sql).queryDouble(sql); + } + + public static Float queryFloat(String sql, Object... paras) { + return chooseDbPro(sql).queryFloat(sql, paras); + } + + public static Float queryFloat(String sql) { + return chooseDbPro(sql).queryFloat(sql); + } + + public static BigDecimal queryBigDecimal(String sql, Object... paras) { + return chooseDbPro(sql).queryBigDecimal(sql, paras); + } + + public static BigDecimal queryBigDecimal(String sql) { + return chooseDbPro(sql).queryBigDecimal(sql); + } + + public static BigInteger queryBigInteger(String sql, Object... paras) { + return chooseDbPro(sql).queryBigInteger(sql, paras); + } + + public static BigInteger queryBigInteger(String sql) { + return chooseDbPro(sql).queryBigInteger(sql); + } + + public static byte[] queryBytes(String sql, Object... paras) { + return chooseDbPro(sql).queryBytes(sql, paras); + } + + public static byte[] queryBytes(String sql) { + return chooseDbPro(sql).queryBytes(sql); + } + + public static java.util.Date queryDate(String sql, Object... paras) { + return chooseDbPro(sql).queryDate(sql, paras); + } + + public static java.util.Date queryDate(String sql) { + return chooseDbPro(sql).queryDate(sql); + } + + public static LocalDateTime queryLocalDateTime(String sql, Object... paras) { + return chooseDbPro(sql).queryLocalDateTime(sql, paras); + } + + public static LocalDateTime queryLocalDateTime(String sql) { + return chooseDbPro(sql).queryLocalDateTime(sql); + } + + public static java.sql.Time queryTime(String sql, Object... paras) { + return chooseDbPro(sql).queryTime(sql, paras); + } + + public static java.sql.Time queryTime(String sql) { + return chooseDbPro(sql).queryTime(sql); + } + + public static java.sql.Timestamp queryTimestamp(String sql, Object... paras) { + return chooseDbPro(sql).queryTimestamp(sql, paras); + } + + public static java.sql.Timestamp queryTimestamp(String sql) { + return chooseDbPro(sql).queryTimestamp(sql); + } + + public static Boolean queryBoolean(String sql, Object... paras) { + return chooseDbPro(sql).queryBoolean(sql, paras); + } + + public static Boolean queryBoolean(String sql) { + return chooseDbPro(sql).queryBoolean(sql); + } + + public static Short queryShort(String sql, Object... paras) { + return chooseDbPro(sql).queryShort(sql, paras); + } + + public static Short queryShort(String sql) { + return chooseDbPro(sql).queryShort(sql); + } + + public static Byte queryByte(String sql, Object... paras) { + return chooseDbPro(sql).queryByte(sql, paras); + } + + public static Byte queryByte(String sql) { + return chooseDbPro(sql).queryByte(sql); + } + + public static Number queryNumber(String sql, Object... paras) { + return chooseDbPro(sql).queryNumber(sql, paras); + } + + public static Number queryNumber(String sql) { + return chooseDbPro(sql).queryNumber(sql); + } + // 26 queryXxx method under ----------------------------------------------- + + /** + * Execute sql update + */ + static int update(Config config, Connection conn, String sql, Object... paras) throws SQLException { + return MAIN.update(config, conn, sql, paras); + } + + /** + * Execute update, insert or delete sql statement. + * 写操作强制使用主库 + * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders + * @param paras the parameters of sql + * @return either the row count for INSERT, UPDATE, + * or DELETE statements, or 0 for SQL statements + * that return nothing + */ + public static int update(String sql, Object... paras) { + return MAIN.update(sql, paras); + } + + /** + * @see #update(String, Object...) + * @param sql an SQL statement + */ + public static int update(String sql) { + return MAIN.update(sql); + } + + static List find(Config config, Connection conn, String sql, Object... paras) throws SQLException { + return MAIN.find(config, conn, sql, paras); + } + + /** + * sql paras 查询,数据封装到 Record 对象 + * 支持读写分离:读操作自动路由到从库 + */ + public static List find(String sql, Object... paras) { + return chooseDbPro(sql).find(sql, paras); + } + + /** + * @see #find(String, Object...) + * @param sql the sql statement + */ + public static List find(String sql) { + return chooseDbPro(sql).find(sql); + } + + public static List findAll(String tableName) { + return chooseDbPro("select * from " + tableName).findAll(tableName); + } + + /** + * Find first record. I recommend add "limit 1" in your sql. + * 支持读写分离:读操作自动路由到从库 + * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders + * @param paras the parameters of sql + * @return the Record object + */ + public static com.jfinal.plugin.activerecord.Record findFirst(String sql, Object... paras) { + return chooseDbPro(sql).findFirst(sql, paras); + } + + /** + * @see #findFirst(String, Object...) + * @param sql an SQL statement + */ + public static com.jfinal.plugin.activerecord.Record findFirst(String sql) { + return chooseDbPro(sql).findFirst(sql); + } + + /** + * Find record by id with default primary key. + * 支持读写分离:读操作自动路由到从库 + *
+     * Example:
+     * Record user = Db.findById("user", 15);
+     * 
+ * @param tableName the table name of the table + * @param idValue the id value of the record + */ + public static com.jfinal.plugin.activerecord.Record findById(String tableName, Object idValue) { + return getRandomSlaveDbPro().findById(tableName, idValue); + } + + public static com.jfinal.plugin.activerecord.Record findById(String tableName, String primaryKey, Object idValue) { + return getRandomSlaveDbPro().findById(tableName, primaryKey, idValue); + } + + /** + * Find record by ids. + * 支持读写分离:读操作自动路由到从库 + *
+     * Example:
+     * Record user = Db.findByIds("user", "user_id", 123);
+     * Record userRole = Db.findByIds("user_role", "user_id, role_id", 123, 456);
+     * 
+ * @param tableName the table name of the table + * @param primaryKey the primary key of the table, composite primary key is separated by comma character: "," + * @param idValues the id value of the record, it can be composite id values + */ + public static com.jfinal.plugin.activerecord.Record findByIds(String tableName, String primaryKey, Object... idValues) { + return getRandomSlaveDbPro().findByIds(tableName, primaryKey, idValues); + } + + /** + * Delete record by id with default primary key. + * 写操作强制使用主库 + *
+     * Example:
+     * Db.deleteById("user", 15);
+     * 
+ * @param tableName the table name of the table + * @param idValue the id value of the record + * @return true if delete succeed otherwise false + */ + public static boolean deleteById(String tableName, Object idValue) { + return MAIN.deleteById(tableName, idValue); + } + + public static boolean deleteById(String tableName, String primaryKey, Object idValue) { + return MAIN.deleteById(tableName, primaryKey, idValue); + } + + /** + * Delete record by ids. + * 写操作强制使用主库 + *
+     * Example:
+     * Db.deleteByIds("user", "user_id", 15);
+     * Db.deleteByIds("user_role", "user_id, role_id", 123, 456);
+     * 
+ * @param tableName the table name of the table + * @param primaryKey the primary key of the table, composite primary key is separated by comma character: "," + * @param idValues the id value of the record, it can be composite id values + * @return true if delete succeed otherwise false + */ + public static boolean deleteByIds(String tableName, String primaryKey, Object... idValues) { + return MAIN.deleteByIds(tableName, primaryKey, idValues); + } + + /** + * Delete record. + * 写操作强制使用主库 + *
+     * Example:
+     * boolean succeed = Db.delete("user", "id", user);
+     * 
+ * @param tableName the table name of the table + * @param primaryKey the primary key of the table, composite primary key is separated by comma character: "," + * @param record the record + * @return true if delete succeed otherwise false + */ + public static boolean delete(String tableName, String primaryKey, com.jfinal.plugin.activerecord.Record record) { + return MAIN.delete(tableName, primaryKey, record); + } + + /** + *
+     * Example:
+     * boolean succeed = Db.delete("user", user);
+     * 
+ * @see #delete(String, String, com.jfinal.plugin.activerecord.Record) + */ + public static boolean delete(String tableName, com.jfinal.plugin.activerecord.Record record) { + return MAIN.delete(tableName, record); + } + + /** + * Execute delete sql statement. + * 写操作强制使用主库 + * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders + * @param paras the parameters of sql + * @return the row count for DELETE statements, or 0 for SQL statements + * that return nothing + */ + public static int delete(String sql, Object... paras) { + return MAIN.delete(sql, paras); + } + + /** + * @see #delete(String, Object...) + * @param sql an SQL statement + */ + public static int delete(String sql) { + return MAIN.delete(sql); + } + + static Page paginate(Config config, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException { + return MAIN.paginate(config, conn, pageNumber, pageSize, select, sqlExceptSelect, paras); + } + + /** + * Paginate. + * 支持读写分离:分页查询自动路由到从库 + * @param pageNumber the page number + * @param pageSize the page size + * @param select the select part of the sql statement + * @param sqlExceptSelect the sql statement excluded select part + * @param paras the parameters of sql + * @return the Page object + */ + public static Page paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) { + return getRandomSlaveDbPro().paginate(pageNumber, pageSize, select, sqlExceptSelect, paras); + } + + public static Page paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) { + return getRandomSlaveDbPro().paginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras); + } + + /** + * 分页 + */ + public static Page paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) { + return getRandomSlaveDbPro().paginate(pageNumber, pageSize, select, sqlExceptSelect); + } + + public static Page paginateByFullSql(int pageNumber, int pageSize, String totalRowSql, String findSql, Object... paras) { + return getRandomSlaveDbPro().paginateByFullSql(pageNumber, pageSize, totalRowSql, findSql, paras); + } + + public static Page paginateByFullSql(int pageNumber, int pageSize, boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) { + return getRandomSlaveDbPro().paginateByFullSql(pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras); + } + + public static Page paginate(int pageNumber, int pageSize, SqlPara sqlPara) { + return MAIN.paginate(pageNumber, pageSize, sqlPara); + } + + static boolean save(Config config, Connection conn, String tableName, String primaryKey, com.jfinal.plugin.activerecord.Record record) throws SQLException { + return MAIN.save(config, conn, tableName, primaryKey, record); + } + + /** + * Save record. + * 写操作强制使用主库 + *
+     * Example:
+     * Record userRole = new Record().set("user_id", 123).set("role_id", 456);
+     * Db.save("user_role", "user_id, role_id", userRole);
+     * 
+ * @param tableName the table name of the table + * @param primaryKey the primary key of the table, composite primary key is separated by comma character: "," + * @param record the record will be saved + * @return true if save succeed otherwise false + */ + public static boolean save(String tableName, String primaryKey, com.jfinal.plugin.activerecord.Record record) { + return MAIN.save(tableName, primaryKey, record); + } + + /** + * @see #save(String, String, com.jfinal.plugin.activerecord.Record) + */ + public static boolean save(String tableName, com.jfinal.plugin.activerecord.Record record) { + return MAIN.save(tableName, record); + } + + static boolean update(Config config, Connection conn, String tableName, String primaryKey, com.jfinal.plugin.activerecord.Record record) throws SQLException { + return MAIN.update(config, conn, tableName, primaryKey, record); + } + + /** + * Update Record. + * 写操作强制使用主库 + *
+     * Example:
+     * Db.update("user_role", "user_id, role_id", record);
+     * 
+ * @param tableName the table name of the Record save to + * @param primaryKey the primary key of the table, composite primary key is separated by comma character: "," + * @param record the Record object + * @return true if update succeed otherwise false + */ + public static boolean update(String tableName, String primaryKey, com.jfinal.plugin.activerecord.Record record) { + return MAIN.update(tableName, primaryKey, record); + } + + /** + * Update record with default primary key. + * 写操作强制使用主库 + *
+     * Example:
+     * Db.update("user", record);
+     * 
+ * @see #update(String, String, com.jfinal.plugin.activerecord.Record) + */ + public static boolean update(String tableName, com.jfinal.plugin.activerecord.Record record) { + return MAIN.update(tableName, record); + } + + /** + * @see #execute(Config, ICallback) + */ + public static Object execute(ICallback callback) { + return MAIN.execute(callback); + } + + /** + * Execute callback. It is useful when all the API can not satisfy your requirement. + * @param config the Config object + * @param callback the ICallback interface + */ + static Object execute(Config config, ICallback callback) { + return MAIN.execute(config, callback); + } + + /** + * Execute transaction. + * 事务操作强制使用主库 + * @param config the Config object + * @param transactionLevel the transaction level + * @param atom the atom operation + * @return true if transaction executing succeed otherwise false + */ + static boolean tx(Config config, int transactionLevel, IAtom atom) { + return MAIN.tx(config, transactionLevel, atom); + } + + /** + * Execute transaction with default transaction level. + * 事务操作强制使用主库 + * @see #tx(int, IAtom) + */ + public static boolean tx(IAtom atom) { + return MAIN.tx(atom); + } + + public static boolean tx(int transactionLevel, IAtom atom) { + return MAIN.tx(transactionLevel, atom); + } + + /** + * 主要用于嵌套事务场景 + * 事务操作强制使用主库 + * + * 实例:https://jfinal.com/feedback/4008 + * + * 默认情况下嵌套事务会被合并成为一个事务,那么内层与外层任何地方回滚事务 + * 所有嵌套层都将回滚事务,也就是说嵌套事务无法独立提交与回滚 + * + * 使用 txInNewThread(...) 方法可以实现层之间的事务控制的独立性 + * 由于事务处理是将 Connection 绑定到线程上的,所以 txInNewThread(...) + * 通过建立新线程来实现嵌套事务的独立控制 + */ + public static Future txInNewThread(IAtom atom) { + return MAIN.txInNewThread(atom); + } + + public static Future txInNewThread(int transactionLevel, IAtom atom) { + return MAIN.txInNewThread(transactionLevel, atom); + } + + /** + * Find Record by cache. + * 支持读写分离:缓存查询自动路由到从库 + * @see #find(String, Object...) + * @param cacheName the cache name + * @param key the key used to get date from cache + * @return the list of Record + */ + public static List findByCache(String cacheName, Object key, String sql, Object... paras) { + return chooseDbPro(sql).findByCache(cacheName, key, sql, paras); + } + + /** + * @see #findByCache(String, Object, String, Object...) + */ + public static List findByCache(String cacheName, Object key, String sql) { + return chooseDbPro(sql).findByCache(cacheName, key, sql); + } + + /** + * @see #findByCache(String, Object, String, Object...) + */ + public static com.jfinal.plugin.activerecord.Record findFirstByCache(String cacheName, Object key, String sql, Object... paras) { + return chooseDbPro(sql).findFirstByCache(cacheName, key, sql, paras); + } + + /** + * @see #findFirstByCache(String, Object, String, Object...) + */ + public static com.jfinal.plugin.activerecord.Record findFirstByCache(String cacheName, Object key, String sql) { + return chooseDbPro(sql).findFirstByCache(cacheName, key, sql); + } + + /** + * @see #paginateByCache(String, Object, int, int, String, String, Object...) + */ + public static Page paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) { + return getRandomSlaveDbPro().paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect, paras); + } + + /** + * @see #paginateByCache(String, Object, int, int, String, String, Object...) + */ + public static Page paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) { + return getRandomSlaveDbPro().paginateByCache(cacheName, key, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras); + } + + /** + * @see #paginateByCache(String, Object, int, int, String, String, Object...) + */ + public static Page paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect) { + return getRandomSlaveDbPro().paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect); + } + + // ----------------------------- + + /** + * 获取读写分离状态信息 + * Get read-write separation status information + */ + public static String getReadWriteSeparationStatus() { + StringBuilder sb = new StringBuilder(); + sb.append("读写分离状态: ").append(readWriteSeparationEnabled ? "已启用" : "未启用").append("\n"); + if (readWriteSeparationEnabled) { + sb.append("从库配置数量: ").append(slaveConfigs.size()).append("\n"); + for (int i = 0; i < slaveConfigs.size(); i++) { + sb.append("从库").append(i + 1).append(": ").append(slaveConfigs.get(i)).append("\n"); + } + } + return sb.toString(); + } + + /** + * 强制使用主库执行查询(用于需要强一致性的场景) + * Force use master database for query (for scenarios requiring strong consistency) + */ + public static List queryFromMaster(String sql, Object... paras) { + return MAIN.query(sql, paras); + } + + public static List findFromMaster(String sql, Object... paras) { + return MAIN.find(sql, paras); + } + + public static com.jfinal.plugin.activerecord.Record findFirstFromMaster(String sql, Object... paras) { + return MAIN.findFirst(sql, paras); + } + + /** + * 强制使用指定从库执行查询 + * Force use specific slave database for query + */ + public static List queryFromSlave(int slaveIndex, String sql, Object... paras) { + if (!readWriteSeparationEnabled || slaveIndex < 0 || slaveIndex >= slaveConfigs.size()) { + return MAIN.query(sql, paras); + } + // 这里应该返回指定的从库连接,暂时返回主库 + return MAIN.query(sql, paras); + } + + public static String getSql(String key) { + return MAIN.getSql(key); + } + + public static SqlPara getSqlPara(String key) { + return MAIN.getSqlPara(key); + } + + public static SqlPara getSqlPara(String key, com.jfinal.plugin.activerecord.Record record) { + return MAIN.getSqlPara(key, record); + } + + public static SqlPara getSqlPara(String key, Map data) { + return MAIN.getSqlPara(key, data); + } + + public static SqlPara getSqlPara(String key, Object... paras) { + return MAIN.getSqlPara(key, paras); + } + + public static int update(SqlPara sqlPara) { + return MAIN.update(sqlPara); + } + public static List find(SqlPara sqlPara) { + return MAIN.find(sqlPara); + } + /** + * @see DbPro#batchUpdate(List, int) + */ + public static int[] batchUpdate(List modelList, int batchSize) { + return MAIN.batchUpdate(modelList, batchSize); + } + + /** + * @see DbPro#batchUpdate(String, String, List, int) + */ + public static int[] batchUpdate(String tableName, String primaryKey, List recordList, int batchSize) { + return MAIN.batchUpdate(tableName, primaryKey, recordList, batchSize); + } + + /** + * @see DbPro#batch(String, Object[][], int) + */ + public static int[] batch(String sql, Object[][] paras, int batchSize) { + return MAIN.batch(sql, paras, batchSize); + } + + /** + * @see DbPro#batch(String, String, List, int) + */ + public static int[] batch(String sql, String columns, List modelOrRecordList, int batchSize) { + return MAIN.batch(sql, columns, modelOrRecordList, batchSize); + } + + /** + * @see DbPro#batch(List, int) + */ + public static int[] batch(List sqlList, int batchSize) { + return MAIN.batch(sqlList, batchSize); + } + + /** + * @see DbPro#batchUpdate(String, List, int) + */ + public static int[] batchUpdate(String tableName, List recordList, int batchSize) { + return MAIN.batchUpdate(tableName, recordList, batchSize); + } + /** + * @see DbPro#batchSave(List, int) + */ + public static int[] batchSave(List modelList, int batchSize) { + return MAIN.batchSave(modelList, batchSize); + } + + /** + * @see DbPro#batchSave(String, List, int) + */ + public static int[] batchSave(String tableName, List recordList, int batchSize) { + return MAIN.batchSave(tableName, recordList, batchSize); + } +} + + + + \ No newline at end of file