尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
东华大学考研复试机试OJ刷题攻略
1. 项目背景与核心价值作为一名计算机专业考研过来人我深知东华大学复试机试环节的重要性。OJOnline Judge在线编程平台是检验考生算法能力和编码水平的关键战场而每日3题打卡正是我当年备战期间总结出的高效训练方法。这个系列记录了我从第43天到第45天的刷题历程包含完整的解题思路、代码实现和易错点分析。这套方法的核心价值在于系统性每日固定题量形成持续训练节奏针对性题目选自东华历年复试真题库实战性所有代码均在OJ平台实测通过可复用解题模板可直接用于考场实战2. 每日训练方法论2.1 题目筛选策略我采用的选题三三制原则难度梯度1基础1进阶1挑战题比例可动态调整题型覆盖必含字符串处理、动态规划等高频考点时间控制总时长控制在2小时内模拟真实考场重要提示第43天开始应侧重图论算法这是东华近年考核重点2.2 标准解题流程每道题严格遵循以下步骤问题重述用自己语言描述题目要求输入输出分析明确边界条件算法设计手写伪代码验证思路编码实现使用C11标准编写测试用例设计5类测试数据复杂度分析计算时间/空间复杂度3. 第43天真题详解3.1 矩阵连通区域计数DFS应用// 典型岛屿问题变种 void dfs(vectorvectorint grid, int i, int j) { if(i0 || j0 || igrid.size() || jgrid[0].size() || grid[i][j]!1) return; grid[i][j] 0; // 标记已访问 dfs(grid,i1,j); dfs(grid,i-1,j); dfs(grid,i,j1); dfs(grid,i,j-1); }常见错误忘记处理对角线连通情况题目明确要求访问标记与输入数据冲突建议使用独立标记数组递归层数过多导致栈溢出矩阵过大时改用BFS3.2 字符串模式匹配KMP优化vectorint buildNext(const string pattern) { vectorint next(pattern.length()); next[0] -1; int j -1; for(int i1; ipattern.length(); i) { while(j0 pattern[i]!pattern[j1]) j next[j]; if(pattern[i] pattern[j1]) j; next[i] j; } return next; }性能对比方法时间复杂度适用场景暴力匹配O(mn)短文本KMPO(mn)含大量重复模式Boyer-MooreO(n/m)字符集较大时3.3 背包问题变种动态规划题目要求在传统01背包基础上增加必选物品约束状态转移方程优化dp[i][j] max( dp[i-1][j], dp[i-1][j-w[i]] v[i] // 常规选择 ) if 物品i是必选的: dp[i][j] dp[i-1][j-w[i]] v[i] // 强制选择4. 第44天难点突破4.1 拓扑排序应用课程安排问题关键点在于检测环的存在bool canFinish(int numCourses, vectorvectorint prerequisites) { vectorvectorint graph(numCourses); vectorint inDegree(numCourses,0); for(auto p : prerequisites){ graph[p[1]].push_back(p[0]); inDegree[p[0]]; } queueint q; for(int i0; inumCourses; i) if(inDegree[i]0) q.push(i); int count 0; while(!q.empty()){ int cur q.front(); q.pop(); count; for(int neighbor : graph[cur]){ if(--inDegree[neighbor] 0) q.push(neighbor); } } return count numCourses; }4.2 线段树实现区间查询动态开点线段树模板struct Node { int l, r; int sum; Node *left, *right; Node(int l, int r): l(l), r(r), sum(0), left(nullptr), right(nullptr) {} }; void update(Node* root, int index, int val) { if(root-l root-r) { root-sum val; return; } int mid (root-l root-r) 1; if(index mid) { if(!root-left) root-left new Node(root-l, mid); update(root-left, index, val); } else { if(!root-right) root-right new Node(mid1, root-r); update(root-right, index, val); } root-sum (root-left ? root-left-sum : 0) (root-right ? root-right-sum : 0); }5. 第45天综合训练5.1 多源最短路径Floyd-Warshallvoid floyd(vectorvectorint dist) { int n dist.size(); for(int k0; kn; k) for(int i0; in; i) for(int j0; jn; j) if(dist[i][k]!INT_MAX dist[k][j]!INT_MAX) dist[i][j] min(dist[i][j], dist[i][k]dist[k][j]); }5.2 并查集优化路径压缩按秩合并vectorint parent; vectorint rank; int find(int x) { return parent[x] x ? x : parent[x] find(parent[x]); } void unionSet(int x, int y) { x find(x); y find(y); if(x y) return; if(rank[x] rank[y]) swap(x,y); parent[y] x; if(rank[x] rank[y]) rank[x]; }5.3 单调栈应用柱状图最大矩形# 1. 概述本文我们来分享 MyBatis 的日志模块对应logging包。如下图所示logging包在 《精尽 MyBatis 源码解析 —— 项目结构一览》 中简单介绍了这个模块如下无论在开发测试环境中还是在线上生产环境中日志在整个系统中的地位都是非常重要的。良好的日志功能可以帮助开发人员和测试人员快速定位 Bug 代码也可以帮助运维人员快速定位性能瓶颈等问题。目前的 Java 世界中存在很多优秀的日志框架例如 Log4j、 Log4j2、Slf4j 等。MyBatis 作为一个设计优良的框架除了提供详细的日志输出信息还要能够集成多种日志框架其日志模块的一个主要功能就是集成第三方日志框架。本文涉及的类如下图所示从图的上面部分我们可以看到非常多的 Logger 类的实现分别对应我们常用的日志框架 Log4j、Slf4j 这就是 MyBatis 对这些日志框架的适配。从图的下面部分我们可以看到 BaseJdbcLogger 以及它的四个子类这个不是将日志框架适配到 MyBatis 而是 MyBatis 通过 JDK 动态代理的方式将 JDBC 的操作打印到日志中。即 《设置Mybatis打印调试sql的两种方式》 。下面我们分成三个部分来分享第一个部分MyBatis 的日志模块对多种日志框架的适配。第二个部分MyBatis 如何将 JDBC 的操作打印到日志中。第三个部分收尾看看 Log 接口和 LogFactory 工厂。2. 适配多种日志框架在logging包下我们可以看到有一系列 Logger 的实现类如下图所示Logger 实现类实际上MyBatis 不仅仅提供了上图这些 Logger 的实现类还有例如commons-logging、log4j2、stdout、slf4j等等。完整的胖友可以看看logging包 。那么MyBatis 是如何选择使用哪种 Logger 的实现类的呢或者说如何适配到项目中已经使用的日志框架呢答案就在LogFactory中。代码如下// LogFactory.java /** * 日志构造器 * * 通过构造方法创建对应的 Log 对象 */ private static Constructor? extends Log logConstructor; static { // 1 逐个尝试判断使用哪个日志框架 // 顺序为slf4j → commonsLoging → log4j2 → log4j → jdkLogging tryImplementation(LogFactory::useSlf4jLogging); tryImplementation(LogFactory::useCommonsLogging); tryImplementation(LogFactory::useLog4J2Logging); tryImplementation(LogFactory::useLog4JLogging); tryImplementation(LogFactory::useJdkLogging); // 2 都找不到使用 NoLogging tryImplementation(LogFactory::useNoLogging); } private static void tryImplementation(Runnable runnable) { if (logConstructor null) { try { runnable.run(); } catch (Throwable t) { // ignore } } }1处按照slf4j → commonsLoging → log4j2 → log4j → jdkLogging的顺序逐个尝试判断使用哪个日志框架。因为不同的项目中会使用不同的日志框架而 MyBatis 也无法限制用户使用哪个日志框架所以只好通过这样的方式适配。2处如果都找不到使用 NoLogging 实现类即不打印日志。以#useSlf4jLogging()方法为例子代码如下// LogFactory.java public static synchronized void useSlf4jLogging() { setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class); } private static void setImplementation(Class? extends Log implClass) { try { // 获得参数为 String 的构造方法 Constructor? extends Log candidate implClass.getConstructor(String.class); // 创建 Log 对象 Log log candidate.newInstance(LogFactory.class.getName()); if (log.isDebugEnabled()) { log.debug(Logging initialized using implClass adapter.); } // 创建成功意味着可以使用设置为 logConstructor logConstructor candidate; } catch (Throwable t) { throw new LogException(Error setting Log implementation. Cause: t, t); } }通过反射的方式创建对应的 Log 实现类的对象。如果创建成功意味着可以使用设置为logConstructor属性。其它#useCommonsLogging()等方法代码类似胖友自己瞅瞅。另外MyBatis 也提供了#useCustomLogging(Class? extends Log clazz)方法可以使用自定义的 Log 实现类。代码如下// LogFactory.java public static synchronized void useCustomLogging(Class? extends Log clazz) { setImplementation(clazz); }当然一般情况下我们不会自定义 Log 的实现类。3. 打印 JDBC 操作在实际场景下我们连接数据库执行 SQL 都会打印执行的 SQL 语句、参数、结果等等。那么MyBatis 是如何实现该功能的呢答案在BaseJdbcLogger以及它的四个子类中。3.1 BaseJdbcLoggerorg.apache.ibatis.logging.jdbc.BaseJdbcLogger实现 Log 接口负责打印 JDBC 操作日志的抽象基类。属性如下// BaseJdbcLogger.java /** * 支持的 Log 的构造方法参数的类型 */ protected static final SetString SET_METHODS; /** * 支持的 Log 的执行方法的类型 */ protected static final SetString EXECUTE_METHODS new HashSet(); /** * {link #SET_METHODS} 的初始化 */ static { SET_METHODS new HashSet(); SET_METHODS.add(setString); SET_METHODS.add(setInt); SET_METHODS.add(setBoolean); SET_METHODS.add(setShort); SET_METHODS.add(setLong); SET_METHODS.add(setDouble); SET_METHODS.add(setFloat); SET_METHODS.add(setTimestamp); SET_METHODS.add(setDate); SET_METHODS.add(setTime); SET_METHODS.add(setArray); SET_METHODS.add(setBigDecimal); SET_METHODS.add(setAsciiStream); SET_METHODS.add(setBinaryStream); SET_METHODS.add(setBlob); SET_METHODS.add(setObject); SET_METHODS.add(setCharacterStream); SET_METHODS.add(setNCharacterStream); SET_METHODS.add(setURL); SET_METHODS.add(setNull); } /** * {link #EXECUTE_METHODS} 的初始化 */ static { EXECUTE_METHODS.add(execute); EXECUTE_METHODS.add(executeUpdate); EXECUTE_METHODS.add(executeQuery); EXECUTE_METHODS.add(addBatch); } /** * Log 对象 */ protected final Log statementLog; /** * 查询的层级 */ protected final int queryStack; /** * 参数集合 * * KEY参数的位置 * VALUE参数的值 */ private final MapInteger, String columnMap new HashMap(); /** * 参数集合 */ private final ListObject columnValues new ArrayList();SET_METHODS静态属性支持的 Log 的构造方法参数的类型。即PreparedStatement 类的方法的集合。EXECUTE_METHODS静态属性支持的 Log 的执行方法的类型。即Statement 和 PreparedStatement 类的方法的集合。statementLog属性Log 对象。queryStack属性查询的层级。考虑到可能多个方法嵌套调用。columnMap属性参数集合。KEY参数的位置VALUE参数的值。columnValues属性参数集合。3.1.1 构造方法// BaseJdbcLogger.java public BaseJdbcLogger(Log log, int queryStack) { this.statementLog log; if (queryStack 0) { this.queryStack 1; } else { this.queryStack queryStack; } }3.1.2 setColumn#setColumn(String key, Object value)方法设置参数。代码如下// BaseJdbcLogger.java protected void setColumn(String key, Object value) { columnMap.put(columnValues.size(), key); columnValues.add(value); }3.1.3 getParameterValueString#getParameterValueString()方法获得参数的打印值。代码如下// BaseJdbcLogger.java protected String getParameterValueString() { ListObject typeList new ArrayList(columnValues.size()); // 遍历 columnValues 数组 for (Object value : columnValues) { if (value null) { typeList.add(null); } else { // 转换成字符串 typeList.add(objectValueString(value) ( value.getClass().getSimpleName() )); } } // 拼接字符串 final String parameters typeList.toString(); return parameters.substring(1, parameters.length() - 1); }3.1.4 objectValueString#objectValueString(Object value)方法将参数转换成字符串。代码如下// BaseJdbcLogger.java protected String objectValueString(Object value) { if (value instanceof Array) { try { return ArrayUtil.toString(((Array) value).getArray()); } catch (SQLException e) { return value.toString(); } } return value.toString(); }3.1.5 getColumnString#getColumnString()方法获得参数的名称。代码如下// BaseJdbcLogger.java protected String getColumnString() { return columnMap.toString(); }3.1.6 clearColumn#clearColumn()方法清空参数。代码如下// BaseJdbcLogger.java protected void clearColumn() { columnMap.clear(); columnValues.clear(); }3.1.7 isDebugEnabled#isDebugEnabled()方法判断是否 debug 开启。代码如下// BaseJdbcLogger.java Override public boolean isDebugEnabled() { return statementLog.isDebugEnabled(); }3.1.8 isTraceEnabled#isTraceEnabled()方法判断是否 trace 开启。代码如下// BaseJdbcLogger.java Override public boolean isTraceEnabled() { return statementLog.isTraceEnabled(); }3.1.9 debug#debug(String text)方法打印 debug 日志。代码如下// BaseJdbcLogger.java Override public void debug(String text) { statementLog.debug(text); }3.1.10 trace#trace(String text)方法打印 trace 日志。代码如下// BaseJdbcLogger.java Override public void trace(String text) { statementLog.trace(text); }3.1.11 error#error(String text, Throwable throwable)方法打印 error 日志。代码如下// BaseJdbcLogger.java Override public void error(String text, Throwable throwable) { statementLog.error(text, throwable); }3.2 ConnectionLoggerorg.apache.ibatis.logging.jdbc.ConnectionLogger继承 BaseJdbcLogger 抽象类Connection 的日志实现类。3.2.1 构造方法// ConnectionLogger.java /** * Connection 对象的代理 */ private final Connection connection; private ConnectionLogger(Connection conn, Log statementLog, int queryStack) { super(statementLog, queryStack); this.connection conn; }3.2.2 newInstance#newInstance(Connection connection, Log statementLog, int queryStack)静态方法创建 Connection 的代理对象。代码如下// ConnectionLogger.java public static Connection newInstance(Connection conn, Log statementLog, int queryStack) { // 创建 InvocationHandler 对象 InvocationHandler handler new ConnectionLogger(conn, statementLog, queryStack); // 创建 ClassLoader 对象 ClassLoader cl Connection.class.getClassLoader(); // 创建代理对象 return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler); }3.2.3 invoke// ConnectionLogger.java Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { // 如果调用的是 Object 的方法直接调用不进行代理 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } // 如果调用的是 prepareStatement 方法进行日志处理 if (prepareStatement.equals(method.getName())) { if (isDebugEnabled()) { debug( Preparing: removeBreakingWhitespace((String) params[0]), true); } // 执行方法 PreparedStatement stmt (PreparedStatement) method.invoke(connection, params); // 创建 PreparedStatement 的代理对象 stmt PreparedStatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; // 如果调用的是 prepareCall 方法进行日志处理 } else if (prepareCall.equals(method.getName())) { if (isDebugEnabled()) { debug( Preparing: removeBreakingWhitespace((String) params[0]), true); } // 执行方法 PreparedStatement stmt (PreparedStatement) method.invoke(connection, params); // 创建 PreparedStatement 的代理对象 stmt PreparedStatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; // 如果调用的是 createStatement 方法进行日志处理 } else if (createStatement.equals(method.getName())) { // 执行方法 Statement stmt (Statement) method.invoke(connection, params); // 创建 Statement 的代理对象 stmt StatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; } else { return method.invoke(connection, params); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }根据不同的方法进行不同的日志处理。例如#prepareStatement(String sql)方法会打印要执行的 SQL 语句并创建 PreparedStatement 的代理对象。#prepareCall(String sql)方法会打印要执行的 SQL 语句并创建 PreparedStatement 的代理对象。#createStatement()方法会创建 Statement 的代理对象。通过这样的方式让 Connection 的所有操作都打印相应的日志。3.2.4 getConnection#getConnection()方法获得真正的 Connection 对象。代码如下// ConnectionLogger.java public Connection getConnection() { return connection; }3.3 PreparedStatementLoggerorg.apache.ibatis.logging.jdbc.PreparedStatementLogger继承 BaseJdbcLogger 抽象类PreparedStatement 的日志实现类。3.3.1 构造方法// PreparedStatementLogger.java /** * PreparedStatement 对象的代理 */ private final PreparedStatement statement; private PreparedStatementLogger(PreparedStatement stmt, Log statementLog, int queryStack) { super(statementLog, queryStack); this.statement stmt; }3.3.2 newInstance#newInstance(PreparedStatement stmt, Log statementLog, int queryStack)静态方法创建 PreparedStatement 的代理对象。代码如下// PreparedStatementLogger.java public static PreparedStatement newInstance(PreparedStatement stmt, Log statementLog, int queryStack) { // 创建 InvocationHandler 对象 InvocationHandler handler new PreparedStatementLogger(stmt, statementLog, queryStack); // 创建 ClassLoader 对象 ClassLoader cl PreparedStatement.class.getClassLoader(); // 创建代理对象 return (PreparedStatement) Proxy.newProxyInstance(cl, new Class[]{PreparedStatement.class, CallableStatement.class}, handler); }3.3.3 invoke// PreparedStatementLogger.java Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { // 如果调用的是 Object 的方法直接调用不进行代理 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } // 执行相应的设置参数的方法 if (SET_METHODS.contains(method.getName())) { if (setNull.equals(method.getName())) { setColumn(params[0], null); } else { setColumn(params[0], params[1]); } return method.invoke(statement, params); // 如果是执行 SQL 的方法 } else if (EXECUTE_METHODS.contains(method.getName())) { if (isDebugEnabled()) { debug(Parameters: getParameterValueString(), true); } // 清空参数 clearColumn(); // 执行方法 if (executeQuery.equals(method.getName())) { ResultSet rs (ResultSet) method.invoke(statement, params); return rs null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); } else { return method.invoke(statement, params); } } else { return method.invoke(statement, params); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }根据不同的方法进行不同的日志处理。例如调用#setXXX(int parameterIndex, ...)等等方法会调用#setColumn(String key, Object value)方法记录参数。调用#executeXXX()等等方法会调用#getParameterValueString()方法打印参数并创建 ResultSet 的代理对象。通过这样的方式让 PreparedStatement 的所有操作都打印相应的日志。3.3.4 getStatement#getStatement()方法获得真正的 PreparedStatement 对象。代码如下// PreparedStatementLogger.java public PreparedStatement getStatement() { return statement; }3.4 StatementLoggerorg.apache.ibatis.logging.jdbc.StatementLogger继承 BaseJdbcLogger 抽象类Statement 的日志实现类。3.4.1 构造方法// StatementLogger.java /** * Statement 对象的代理 */ private final Statement statement; private StatementLogger(Statement stmt, Log statementLog, int queryStack) { super(statementLog, queryStack); this.statement stmt; }3.4.2 newInstance#newInstance(Statement stmt, Log statementLog, int queryStack)静态方法创建 Statement 的代理对象。代码如下// StatementLogger.java public static Statement newInstance(Statement stmt, Log statementLog, int queryStack) { // 创建 InvocationHandler 对象 InvocationHandler handler new StatementLogger(stmt, statementLog, queryStack); // 创建 ClassLoader 对象 ClassLoader cl Statement.class.getClassLoader(); // 创建代理对象 return (Statement) Proxy.newProxyInstance(cl, new Class[]{Statement.class}, handler); }3.4.3 invoke// StatementLogger.java Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { // 如果调用的是 Object 的方法直接调用不进行代理 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } // 如果是执行 SQL 的方法 if (EXECUTE_METHODS.contains(method.getName())) { if (isDebugEnabled()) { debug(Parameters: getParameterValueString(), true); } // 执行方法 if (executeQuery.equals(method.getName())) { ResultSet rs (ResultSet) method.invoke(statement, params); return rs null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); } else { return method.invoke(statement, params); } // 如果是设置 SQL 的方法 } else if (getResultSet.equals(method.getName())) { // 执行方法 ResultSet rs (ResultSet) method.invoke(statement, params); return rs null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); // 如果是设置 SQL 的方法 } else if (getUpdateCount.equals(method.getName())) { // 执行方法 int updateCount (Integer) method.invoke(statement, params); if (updateCount ! -1) { debug( Updates: updateCount, false); } return updateCount; } else { return method.invoke(statement, params); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }根据不同的方法进行不同的日志处理。例如调用#executeXXX()等等方法会调用#getParameterValueString()方法打印参数并创建 ResultSet 的代理对象。调用#getResultSet()方法会创建 ResultSet 的代理对象。调用#getUpdateCount()方法会打印更新的数量。通过这样的方式让 Statement 的所有操作都打印相应的日志。3.4.4 getStatement#getStatement()方法获得真正的 Statement 对象。代码如下// StatementLogger.java public Statement getStatement() { return statement; }3.5 ResultSetLoggerorg.apache.ibatis.logging.jdbc.ResultSetLogger继承 BaseJdbcLogger 抽象类ResultSet 的日志实现类。3.5.1 构造方法// ResultSetLogger.java /** * ResultSet 对象的代理 */ private final ResultSet rs; /** * 第一列的位置 */ private final int firstColumn; /** * 列的数量 */ private int columnCount; /** * 列名数组 */ private String[] columnNames; /** * 列的类型数组 */ private String[] columnClassName; /** * 统计读取的列的数量 */ private final SetInteger blobColumns new HashSet(); private ResultSetLogger(ResultSet rs, Log statementLog, int queryStack) { super(statementLog, queryStack); this.rs rs; // 第一列的位置 this.firstColumn (rs instanceof CallableStatement) ? FIRST_COLUMN_INDEX_CALLABLE_STATEMENT : FIRST_COLUMN_INDEX_NORMAL_STATEMENT; }firstColumn属性第一列的位置。因为CallableStatement和PreparedStatement的位置不同。3.5.2 newInstance#newInstance(ResultSet rs, Log statementLog, int queryStack)静态方法创建 ResultSet 的代理对象。代码如下// ResultSetLogger.java public static ResultSet newInstance(ResultSet rs, Log statementLog, int queryStack) { // 创建 InvocationHandler 对象 InvocationHandler handler new ResultSetLogger(rs, statementLog, queryStack); // 创建 ClassLoader 对象 ClassLoader cl ResultSet.class.getClassLoader(); // 创建代理对象 return (ResultSet) Proxy.newProxyInstance(cl, new Class[]{ResultSet.class}, handler); }3.5.3 invoke// ResultSetLogger.java Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { // 如果调用的是 Object 的方法直接调用不进行代理 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } // 执行方法 Object o method.invoke(rs, params); // 如果是 next 方法 if (next.equals(method.getName())) { // 返回 true 说明有记录 if ((Boolean) o) { // 增加行数 rows; // 处于 debug 模式则打印日志 if (isTraceEnabled()) { ResultSetMetaData rsmd rs.getMetaData(); // 初始化 columnCount if (columnCount 0) { columnCount rsmd.getColumnCount(); } // 打印列名 printColumnHeaders(rsmd, columnCount); // 打印列值 printColumnValues(columnCount); } } else { // 打印总行数 debug( Total: rows, false); } } // 清空 columnMap 和 columnValues clearColumn(); return o; } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }根据不同的方法进行不同的日志处理。例如调用#next()方法会打印每条记录的所有列的值。通过这样的方式让 ResultSet 的所有操作都打印相应的日志。3.5.4 printColumnHeaders#printColumnHeaders(ResultSetMetaData rsmd, int columnCount)方法打印列名。代码如下// ResultSetLogger.java private void printColumnHeaders(ResultSetMetaData rsmd, int columnCount) throws SQLException { // 初始化 columnNames 和 columnClassName 属性 if (columnNames null) { columnNames new String[columnCount 1]; columnClassName new String[columnCount 1]; for (int i 1; i columnCount; i) { columnNames[i] rsmd.getColumnLabel(i); columnClassName[i] rsmd.getColumnClassName(i); } } // 拼接日志 if (columnCount 1) { trace( Columns: columnNames[1]); } else if (columnCount 1) { StringBuilder sb new StringBuilder( Columns: ); sb.append(columnNames[1]); for (int i 2; i columnCount; i) { sb.append(, ); sb.append(columnNames[i]); } trace(sb.toString()); } }3.5.5 printColumnValues#printColumnValues(int columnCount)方法打印列值。代码如下// ResultSetLogger.java private void printColumnValues(int columnCount) { if (columnCount 1) { trace( Row: getColumnValue(1)); } else if (columnCount 1) { StringBuilder sb new StringBuilder( Row: ); sb.append(getColumnValue(1)); for (int i 2; i columnCount; i) { sb.append(, ); sb.append(getColumnValue(i)); } trace(sb.toString()); } }3.5.6 getColumnValue#getColumnValue(int column)方法获得指定列的值。代码如下// ResultSetLogger.java private String getColumnValue(int column) { try { // 判断是否为 BLOB 类型 if (bl
RELATED

相关推荐

Redis高频面试题解析与生产环境优化实践

Redis高频面试题解析与生产环境优化实践

1. Redis面试中的三个高频易错题解析Redis作为当前最流行的内存数据库之一,几乎成为了后端开发岗位的必考知识点。但很多候选人在面对看似基础的Redis问题时,往往因为对底层原理理解不够深入而错失得分机会。本文将拆解三个90%面试者都会答错的Redis高频…

📅 2026/11/13 3:05:48
解决JavaScript类继承错误:Class extends value undefined排查指南

解决JavaScript类继承错误:Class extends value undefined排查指南

1. 问题初现:一个令人困惑的继承错误如果你正在一个Node.js项目中执行npm install或者运行某个脚本,突然在控制台看到一行刺眼的红色错误信息:Class extends value undefined is not a constructor or null,心里多半会咯噔一下。这…

📅 2026/10/23 6:08:23
数学建模竞赛实战:AI图像识别与曲率计算的融合应用

数学建模竞赛实战:AI图像识别与曲率计算的融合应用

1. 项目背景与核心挑战:当数学建模遇上AI图像识别最近刚带着团队打完今年的“认证杯”网络挑战赛,我们选的是D题,一个关于“AI图片判断”和“曲率计算”的题目。说实话,这题目挺有意思,它把当下火热的计算机视觉&#…

📅 2026/10/5 20:29:09
MORE NEWS

更多资讯

📰

工地太忙根本没时间复习考试?高压电工证到手文案通过率揭秘

工地太忙根本没时间复习考试?高压电工证到手文案通过率揭秘 工地太忙根本没时间复习考试,高压电工证又不能拖,很多小伙伴都愁得不行。其实,高压电工证的办理流程和考试准备并不复杂,关键是找到靠谱的培训机构和方法。下面我从商丘公路工程从业者的角度出…

📰

电工证复检图案官方回应来了,怕考不过白交培训费?这篇讲透了

电工证复检图案官方回应来了,怕考不过白交培训费?这篇讲透了 怕考不过白交培训费?别急,官方回应来了,电工证复检图案不是随便糊弄就能过的,这事儿咱们得拿点真本事。特别是像信阳房建工程这些一线岗位,电工证不只是上岗门槛,更是你职业生涯的“护城河…

📰

花垣县电工证报名多少钱?别被中介坑了,这几点必须知道

花垣县电工证报名多少钱?别被中介坑了,这几点必须知道 不知道去哪报名怕被中介坑,花垣县电工证报名多少钱?这个问题是很多想考电工证的朋友最关心的。你可能听说过各种培训机构,但真正靠谱的却难找,稍不留神就可能多花冤枉钱,甚至拿到假证。今天就来聊…

📰

电工证查体全流程解析:学历不高也能考,全国通用不愁找工作

电工证查体全流程解析:学历不高也能考,全国通用不愁找工作 你是不是也担心自己学历不高,考不了电工证?别急, 电工证查体 其实对学历要求并不高,只要符合条件,全国通用的电工证照样能拿到手。今天我就从商丘一位初次报考者的角度,手把手带你走一遍整…

📰

我考完电工证在哪查保姆级教程:工地太忙根本没时间复习考试?

我考完电工证在哪查保姆级教程:工地太忙根本没时间复习考试? 工地太忙根本没时间复习考试,这几乎是所有一线施工人员的共同痛点,尤其是像我们这种在济源公路工程一线干了五六年的人来说,每天扛着工具箱穿梭在工地各处,连吃饭时间都被压缩得紧紧巴巴,哪…

📰

宜昌猇亭电工证办理值不值得考?急需特种作业证才能上岗找工作

宜昌猇亭电工证办理值不值得考?急需特种作业证才能上岗找工作 你是不是正在找工作,却发现很多岗位都写着“持有特种作业操作证优先”或“必须持有电工证”?其实这不是小问题,而是当前很多行业的硬性门槛,尤其是像电工这样的岗位, 宜昌猇亭电工证办理…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬