ibatis在debug时打印完整的SQL语句

转载于:http://www.cnblogs.com/warison2008/archive/2010/10/13/1850262.html

这些年做的项目中,对持久层的选型更多的是基于ibatis,而且自己涂鸦的系统开发框架数据层操作也是居于ibatis实现的,不为别的,就因为ibatis使用的是纯jdbc操作。

      时下流行凡是都“原始回归”,“如果能把ibatis进行更好地理解和扩展,也不乏为一个优秀的杜撰框架”,基于这样的想法,好长时间里,我一直是钟情于ibatis的源码学习,自然从中也学到了很多有用的东西,设计模式、算法分析、构建思想和一些优秀的API实体类工具等。

       好,先来几句赞美ibatis的浮夸。

      ibatis 是一个 O/R Mapping 解决方案, ibatis 最大的特点就是小巧,上手很快。如果你不需要太多复杂的功能, ibatis 是能满足你的要求又足够灵活的最简单的解决方案。ibatis 以SQL开发的工作量和数据库移植性上的让步,为系统 设计提供了更大的自由空间。

      ibatis 底层采用纯JDBC操作,要求操作人员直接编写sql进行操作,光从这点看,ibatis本身就大大地提高数据层操作的透明度。

ibatis在debug时打印完整的SQL语句

      好啦,改干正事了,这里我主要解决的就是一个常见的问题,即使用ibatis时需要在控制台或日志文件中打印其当前执行的完整sql,而不是常见的参数 问号 ? 语句。(这里主要基于ibatis2.0以上版本)。

步骤:

      1.网上下一个源码文件(没有可找我,我发一份给你)

      2. 最终API执行流程,这里以insert为例。 具体顺序如下图:

ibatis在debug时打印完整的SQL语句

      3. 最终根源找到,即修改com.ibatis.sqlmap.engine.execution.SqlExecutor即可。

在代码66行处有如下方法

public int executeUpdate(StatementScope statementScope, Connection conn, String sql, Object[] parameters) throws SQLException {

}

insert最终执行的就是这个方法,恩,就是它了,改吧

      4. 在类体中引入日志打印工具

private static final Log log = LogFactory.getLog(SqlExecutor.class);

     5. 添加debug下执行sql打印信息

在ps.execute(); 执行前添加如下:

ibatis在debug时打印完整的SQL语句代码
if

 (log.isDebugEnabled()) {
       

int

 count 

=

 ps.getParameterMetaData().getParameterCount();
            

for

 (

int

 i 

=

 

0

; i 

<

 count; i

++

) {
                 sql 

=

 sql.replaceFirst(

"

\\?

"

, parameters[i].getClass().getName().equals(

"

java.lang.String

"

) 

?

 

"

'

"

+

parameters[i].toString()

+

"

'

"

 : parameters[i].toString());
              }
            log.debug(

"

===当前执行SQL为===

"

 

+

 sql 

+

 

"

.

"

);
}

还是贴一下完整的方法吧,省得有人抱怨我,O(∩_∩)O哈哈~

ibatis在debug时打印完整的SQL语句代码
public

 

int

 executeUpdate(StatementScope statementScope, Connection conn, String sql, Object[] parameters) 

throws

 SQLException {
    ErrorContext errorContext 

=

 statementScope.getErrorContext();
    errorContext.setActivity(

"

executing update

"

);
    errorContext.setObjectId(sql);
    PreparedStatement ps 

=

 

null

;
    setupResultObjectFactory(statementScope);
    

int

 rows 

=

 

0

;
    

try

 {
      errorContext.setMoreInfo(

"

Check the SQL Statement (preparation failed).

"

);
      ps 

=

 prepareStatement(statementScope.getSession(), conn, sql);
      setStatementTimeout(statementScope.getStatement(), ps);
      errorContext.setMoreInfo(

"

Check the parameters (set parameters failed).

"

);
      statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
      errorContext.setMoreInfo(

"

Check the statement (update failed).

"

);


//

打印调试信息 start




if

 (log.isDebugEnabled()) {
    

int

 count 

=

 ps.getParameterMetaData().getParameterCount();
                

for

 (

int

 i 

=

 

0

; i 

<

 count; i

++

) {
                     sql 

=

 sql.replaceFirst(

"

\\?

"

, parameters[i].getClass().getName().equals(

"

java.lang.String

"

) 

?

 

"

'

"

+

parameters[i].toString()

+

"

'

"

 : parameters[i].toString());
              }
                log.debug(

"

===当前执行SQL为===

"

 

+

 sql 

+

 

"

.

"

);
}


//

打印调试信息 end




      ps.execute();
      rows 

=

 ps.getUpdateCount();
    } 

finally

 {
      closeStatement(statementScope.getSession(), ps);
    }
    

return

 rows;
}

     Ok,主要的工作就是这样,下面开启commons-logging\log4j的debug模式测试一下吧。其他方式的API方法修改也累似了。

     可能你会鄙视我,就这点三脚猫还出来“现眼”,笑笑,没事了,反正我就是想和大伙分享下自己的心得。自然对一个框架的扩展修改不会仅限于此(如sqlmap一个节点下同时执行多个sql、主子表同时保存一次操作中保证彼此外键的同时赋值关联、selectkey变种扩展为classkey即唯一主键由某个类实现而不是数据库sql,等等这些都是很容易的事情),如果是这样那我还不如回家种田去。可是罪恶的约束限制我只能写这么多,在中国嘛,就是这样了,到哪里都《保密协议》,悲哀。。。。。。

     后期,如有时间,我会说说ibatis中关于connecting,事物,对象缓存等一些自己的理解,更多的是一些读懂代码的体会。

      【最近在弄自创的WMframework,2.0版本,设计,代码实现基本上完成,还差一些文档说明,等做好那天再和大伙分享吧,不过不要笑我啊,因为我就是涂鸦而已。】

相关推荐