Mybatis 中如何优雅的增强日志功能?

477 阅读1分钟

首先搞清楚那些地方需要打印日志?通过对日志的观察,如下几个位置需要打日志:

  • 在创建 prepareStatement 时,打印执行的 SQL 语句;
  • 访问数据库时,打印参数的类型和值
  • 查询出结构后,打印结果数据条数

因 此 在 日 志 模 块 中 有 BaseJdbcLoggerConnectionLoggerPreparedStatementLoggerResultSetLogge通过动态代理负责在不同的位置打印日志;几个相关类的类图如下:

Mybatis 中如何优雅的增强日志功能?

BaseJdbcLogger:所有日志增强的抽象基类,用于记录 JDBC 那些方法需要增强,保存运行期间 sql 参数信息;

ConnectionLogger:负责打印连接信息和 SQL 语句。通过动态代理,对 connection 进行增强,如果是调用 prepareStatementprepareCallcreateStatement 的方法,打印要执行的 sql 语句并返回 prepareStatement 的代理对象(PreparedStatementLogger),让prepareStatement 也具备日志能力,打印参数;

PreparedStatementLogger:对 prepareStatement 对象增强,增强的点如下:

  • 增强 PreparedStatement 的 setxxx 方法将参数设置到 columnMapcolumnNamescolumnValues,为打印参数做好准备;
  • 增强 PreparedStatement 的 execute 相关方法,当方法执行时,通过动态代理打印参数,返回动态代理能力的 resultSet;
  • 如果是查询,增强 PreparedStatementgetResultSet 方法,返回动态代理能力的 resultSet;如果是更新,直接打印影响的行数

ResultSetLogge:负责打印数据结果信息;

最后一个问题:上面讲这么多,都是日志功能的实现,那日志功能是怎么加入主体功能的?

答:既然在 Mybatis 中 Executor 才是访问数据库的组件,日志功能是在 Executor 中被嵌入的,具体代码在 org.apache.ibatis.executor.SimpleExecutor.prepareStatement(StatementHandler, Log)方法中,如下图所示: