bluerain008
2008-11-10 13:18 阅读 222
已采纳

SQLMAP中,我想抓取sql,怎么做?

DAO里面写了个方法:
public List getList(HashMap map) {
return this.getSqlMapClientTemplate().queryForList(“sqlName”,map);
}
这样的一个方法,我执行了一个名叫:sqlName 的sql。


select * from test where id=#id#

我想在调用getList()这个方法的时候,我能把sql也获取到一个String(Object)里面
???
不知道如何实现??或者还有其他的办法???

[b]问题补充:[/b]
因为考虑到不去破坏整体框架,所以sql肯定要写到xml文件里面。
但是部分sql需要抓取出来使用,用ireport导出报表,需要传sql。。
不知道还有什么办法能实现这样的需要??
简单的说就是sql需要使用2次,而且尽量些到xml配置文件中

谢谢。
[b]问题补充:[/b]
DAO里面写了个方法:
public List getList(HashMap map) {
return this.getSqlMapClientTemplate().queryForList(“sqlName”,map);
}
这样的一个方法,我执行了一个名叫:sqlName 的sql。


select * from test where id=#id#

我想在调用getList()这个方法的时候,我能把sql也获取到一个String(Object)里面
???
不知道如何实现??或者还有其他的办法???

[b]问题补充:[/b]
因为考虑到不去破坏整体框架,所以sql肯定要写到xml文件里面。
但是部分sql需要抓取出来使用,用ireport导出报表,需要传sql。。
不知道还有什么办法能实现这样的需要??
简单的说就是sql需要使用2次,而且尽量些到xml配置文件中

谢谢。


linpyi 你说对了,这个项目是改造项目。jasper文件都用以前的。

所以没有办法再来做一次。只有想办法传个sql进去比较简单,快速了。

simon511 提的建议可以把sql拿出来,但是我试验了下,传了个map进去,好像参数没有传进去,出来的还是id=?这样的形式。不知道我是否传错地方?
代码如下:
String sql1 = null;

ExtendedSqlMapClient extendedSqlMapClient = (ExtendedSqlMapClient) this.getSqlMapClient();

MappedStatement mappedStatement = extendedSqlMapClient

.getMappedStatement("getADSLReasonAspList");

if (mappedStatement != null) {

RequestScope request = new RequestScope();

request.setStatement(mappedStatement);

sql1 = mappedStatement.getSql().getSql(request, map);

}

System.out.println(sql1);

谢谢。

cats_tiger 的方法我想如果有1000人并发,是否有问题?
导致sql乱续?方法有点难度哈。目前也不知道会不会导致其他问题产生。


谢谢大家的指导。

ps: 怎么提问没有“回复”这样的按钮啊??

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

8条回答 默认 最新

  • 已采纳
    sptzone sptzone 2008-11-10 17:14

    不好意思,上面的SqlMapSession应该是SqlMapExecutorDelegate

    楼主可以将
    SqlMapClient强制转成SqlMapClientImpl,然后获取delegate.

    [code="java"]SqlMapClientImpl sqlMapClientImpl = (SqlMapClientImpl)sqlMapClient;
    SqlMapExecutorDelegate delegate = sqlMapClientImpl.getDelegate();[/code]

    在delegate中,可以取到所有的环境信息
    包括

    [quote] private HashMap mappedStatements;
    private HashMap cacheModels;
    private HashMap resultMaps;
    private HashMap parameterMaps;[/quote]

    推荐用户可以根据这条线简单研究一下ibatis的源代码,不会花很长时间的。里面有些属性可能是private的,并且没有提供get和set方法,这样的话,可以用反射机制获得和设置。

    [code="java"]import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;

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

    public class ReflectUtil
    {

    private static final Log logger = LogFactory.getLog(ReflectUtil.class);

    public static void setFieldValue(Object target, String fname, Class ftype,
    Object fvalue)
    {
    if (target == null || fname == null || "".equals(fname)
    || (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass())))
    {
    return;
    }
    Class clazz = target.getClass();
    try
    {

      Method method = clazz.getDeclaredMethod("set"
          + Character.toUpperCase(fname.charAt(0)) + fname.substring(1),
          new Class[] { ftype });
      if (!Modifier.isPublic(method.getModifiers()))
      {
        method.setAccessible(true);
      }
      method.invoke(target, new Object[] { fvalue });
    
    } catch (Exception me)
    {
      if (logger.isDebugEnabled())
      {
        logger.debug(me);
      }
      try
      {
        Field field = clazz.getDeclaredField(fname);
        if (!Modifier.isPublic(field.getModifiers()))
        {
          field.setAccessible(true);
        }
        field.set(target, fvalue);
      } catch (Exception fe)
      {
        if (logger.isDebugEnabled())
        {
          logger.debug(fe);
        }
      }
    }
    

    }
    }[/code]

    点赞 评论 复制链接分享
  • linpyi linpyi 2008-11-10 13:26

    能不能说明下你要这个SQL的具体目的

    如果只是想要获取SQL语句,你既然已经知道配置文件中的 select * from test where id=#id#

    你只要写一个

    [code="java"]
    public List getList(HashMap map) {
    String sql = "select * from test where id=";
    sql+=map;//我不知道你map里面放的是什么,随便写了下.
    return this.getSqlMapClientTemplate().queryForList(“sqlName”,map);
    }
    其中SQL可以是全局静态公有变量,你在其他类中就可以获取.不过感觉好象没什么意义
    [/code]

    如果你想通过外部程序来获取,
    那就去解析你的配置文件中相应的节点信息,然后组合map

    具体问题具体分析...这是我理解你提出的这个需求..如果有其他目的可以补充

    点赞 评论 复制链接分享
  • linpyi linpyi 2008-11-10 14:35

    感觉鱼和熊掌不可兼得......

    不过你倒出报表需要的是数据而不是SQL语句,你只要把数据查询出来填写到报表bean中就可以了.

    难道你需要得到SQL语句,再使用JDBC直连,再查询出数据,再填充到报表bean中去吗?

    点赞 评论 复制链接分享
  • bluelily22 bluelily22 2008-11-10 14:42

    有sqlname了,当然可以取出sql呀
    [code="java"]String sql = null;
    ExtendedSqlMapClient extendedSqlMapClient = (ExtendedSqlMapClient) sqlMapClient;
    MappedStatement mappedStatement = extendedSqlMapClient
    .getMappedStatement(sqlId);
    if (mappedStatement != null) {
    RequestScope request = new RequestScope();
    request.setStatement(mappedStatement);
    sql = mappedStatement.getSql().getSql(request, paramObject);
    }[/code]

    点赞 评论 复制链接分享
  • catstiger catstiger 2008-11-10 14:43

    扩展com.ibatis.sqlmap.engine.execution.SqlExecutor
    覆盖executeQuery方法,把SQL写入ThreadLocal:
    [code="java"]
    public void executeQuery(RequestScope request, Connection conn, String sql,
    //把SQL写入ThreadLocal,代码省略

    super.executeQuery(request, conn, sql, parameters, skipResults, maxResults, callback);
    

    }
    //使用的时候,可以从ThreadLocal得到SQL
    [/code]

    点赞 评论 复制链接分享
  • catstiger catstiger 2008-11-10 14:47

    使用的时候,需要用反射方法向SqlMapClient 注入新的sqlExecutor:
    [code="java"]
    //用到了SPring的IbatisTemplate和ReflectionUtils
    if (sqlExecutor != null) {
    SqlMapClient sqlMapClient = getTemplate().getSqlMapClient();

      if (sqlMapClient instanceof ExtendedSqlMapClient) {
        Field field = ReflectionUtils.findField(((ExtendedSqlMapClient) sqlMapClient).getDelegate().getClass(),
            "sqlExecutor", SqlExecutor.class);
        field.setAccessible(true);
        ReflectionUtils.setField(field, ((ExtendedSqlMapClient) sqlMapClient).getDelegate(), sqlExecutor);
      }
    }
    

    [/code]

    点赞 评论 复制链接分享
  • catstiger catstiger 2008-11-10 15:40

    性能没事的,Spring之类的都用ThreadLocal,这个保证了线程安全。
    你要得到是最终的SQL?带“?”不行呀?这个复杂了。你需要为你的连接池做代理类,DataSource、Connection、PreparedStatement都要代理一下,只有这样才能知道发送到DB的最终SQL是什么。同样的,吧SQL存入ThreadLocal,然后调用者在ThreadLocal拿到SQL。
    简单地说,自己写一个DataSource的实现类,但是真正的实现用DBCP或者C3PO,当getConnection的时候,将DBCP产生的Connection通过代理,转换为你自己的Connection实现,然后prepareStatement的时候,将实际的PreparedStatement对象再次转换为你自己的实现。
    先要看看代理模式。
    也许需要研究一下驱动程序的源代码,MySQL的源码可以找到的。

    点赞 评论 复制链接分享
  • sptzone sptzone 2008-11-10 16:27

    [quote]simon511 提的建议可以把sql拿出来,但是我试验了下,传了个map进去,好像参数没有传进去,出来的还是id=?这样的形式。不知道我是否传错地方? [/quote]
    ibatis在读取配置文件的时候,会将你的sql转换成
    [code="sql"]select * from test where id=?[/code]
    的形式,而#id#会被ibatis作为ParameterMap参数放在SqlMapSession中。

    [code="java"]String sql1 = null;

    ExtendedSqlMapClient extendedSqlMapClient = (ExtendedSqlMapClient) this.getSqlMapClient();

    MappedStatement mappedStatement = extendedSqlMapClient

    .getMappedStatement("getADSLReasonAspList");

    if (mappedStatement != null) {

    RequestScope request = new RequestScope();

    request.setStatement(mappedStatement);

    sql1 = mappedStatement.getSql().getSql(request, map);

    }

    System.out.println(sql1); [/code]
    如果你的设置中设置了
    [code="XML"]useStatementNamespaces="true"[/code]
    上面这一段代码可能是会出错的,需要你加入getMappedStatement("namespace.getADSLReasonAspList");

    如果想达到楼主的效果,推荐首先一点是命名规范化,
    这样你就可以取到SqlMapSession,通过SqlMapSession找到相应的ParameterMap.然后取出相应的值,组装正确的SQL语句。

    点赞 评论 复制链接分享

相关推荐