刀光剑影

一篇好的文章应该如一坛佳酿,未偿已久醉于心;或如一壶好茶,品尝之间回味无穷;或如与心爱的人共进晚餐,仅餐秀色足以饱食。我不妄想自己的文章能惊世骇俗,但始终期待有“和旋之音,击缶之伴”

博客园 首页 新随笔 联系 订阅 管理
  67 随笔 :: 0 文章 :: 610 评论 :: 17万 阅读

1、源码修改记录

1.1、 sqlmap中新增执行节点statements

修改了sqlmap校验解析文件sql-map-2.dtd

修改了sqlmap解析器:SqlMapParser.java

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<statements id="insertUsersList" parameterClass="test.A">//一层节点
<selectKey keyProperty="userId" resultClass="String" type="pre">
            SELECT P_GET_KEY('SEQ_USER_KEY') from DUAL
        </selectKey>
      <insert id="insertUserO" parameterClass="test.A">//二层节点
        INSERT INTO A
        (
          USER_ID     ,
          USER_NAME  ,
          PASSWORD  ,
          create_time  
        )
        values(
        P_GET_KEY('SEQ_USER_KEY'),
       #userName#,
       #password#,
       SYSDATE
        )
        </insert>
        <insert id="insertUserB" parameterClass="test.A">
        INSERT INTO SUBA
        (
          USER_ID     ,
          EMP_ID   
        )
        values(
       P_GET_KEY('SEQ_USER_KEY'),
       P_GET_KEY('SEQ_USER_KEY')
        )
      </insert>
  </statements>


1.2、  ClassKey生成使用

修改了sqlmap校验解析文件sql-map-2.dtd

新定义classkey处理类:com.ibatis.sqlmap.engine.mapping.statement. ClassKeyStatement记录当前需要生成的key的class路径

在sqlmap解析器中新增classkey节点的检查校验

com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser

修改了sql执行代理器中关于classkey的取值及参数对象赋值

com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate

example:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- classkey产生主键 -->
<insert id="insertUserClassKey" parameterClass="test.A">
<![CDATA[  INSERT INTO A
  (
    USER_ID     ,
    USER_NAME  ,
    PASSWORD  ,
    create_time  
  )
  values(
 #userId#,
 #userName#,
 #password#,
 SYSDATE
  ) ]]>
  <classKey keyProperty="userId" resultClass="String" type="pre"
  className="test.util.GenerateSerial"
  methodName="getUUID"
  args="1,2"
  paramTypes="java.lang.String,int"
  >
  </classKey>
</insert>

1.3、  insert中多SQL同步保存

sql表示器com.ibatis.sqlmap.engine.mapping.statement. MappedStatement新增属性resSql,用于记录sqlmap中原始定义的sql,便于后期检查是否存在多个sql的分割标志。当前设置为分号“;”

修改sql执行方法,检查当前是否存在多个sql同时提交的情况;

修改sql执行器com.ibatis.sqlmap.engine.execution.SqlExecutor中对于参数的赋值方法

重构参数映射类

com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap中设定参数的方式,即存在多个sql公用某个参数类时,需要进行键值提取,并处理先后顺序

1.4、 批处理优化

修改了sql执行器com.ibatis.sqlmap.engine.execution.SqlExecutor,

添加了sql执行保存器,用于存储已经添加过在批处理桶列中的sql识别集合map。

即扩展当前检查sql执行的方法:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (currentSql != null && currentSql.equals(sql)) {
 
//检查是否与前一个执行sql相同
 
        int last = statementList.size() - 1;
 
        ps = (PreparedStatement) statementList.get(last);
 
        //add by warison 20101019 检查当前sql是否已经使用过了
 
      } else if (psMap.containsKey(sql)) {
 
//检查是否已经在过去生成过当前sql
 
      ps = (PreparedStatement) psMap.get(sql);
 
      } else{

 1.5、Debug模式下打印完整的SQL语句

  • 改进目标

即使用ibatis时需要在控制台或日志文件中打印其当前执行的完整sql,而不是常见的参数 问号 ? 语句。

  • 执行顺序分析

Ibatis中常见API执行流程:

  • 修改说明

主要修改com.ibatis.sqlmap.engine.execution.SqlExecutor,找到方法executeUpdate,即ps.execute();语句执行之前,新增如下代码:

1
2
3
4
5
6
7
8
9
//打印调试信息 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

2、扩展使用说明

2.1、sqlmap中新增执行节点statements

sqlmap中新增执行节点 statements,其中可以包含多个子节点(insert、update、delete、statement均可),改功能扩展后用处不太理想

使用参考:参考以上

 

2.2、ClassKey生成使用

classKey获取主键即为,执行某个class中的方法后生成主键序列的方式,格式定义是为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<classKey
 
keyProperty="userId" //生成key存放如parameterClass的属性名称,必填
 
resultClass="String" //返回key结果类型,必填
 
type="pre"//insert执行前、后执行当前生成主键方式,必填
 
    className="test.util.GenerateSerial"//当前执行类全路径,必填
 
    methodName="getUUID"//当前执行方法,必填
 
    args="1,2"//参数值,多个以逗号隔开,选填
 
    paramTypes="java.lang.String,int"//参数类型,多个以逗号隔开,选填
 
    >
 
</classKey>

以上即表示执行test.util.GenerateSerial中getUUID,并传递参数1,2。返回字符串类型数据存放在userId中

2.3、insert中多SQL同步保存

     在sqlmap中扩展insert节点,可确保一次性提交同步执行多条sql,各sql之间以逗号;隔开(当前分隔符可自行定义),这有利于保证主子表同步保存时,关联外键的相同性。而且多个sql语句仅需要定义一个参数类或map等形式。这样我们就没必要再service层定义aop之类以事务管理了,也减少了很多没必要的代码编写

     这这里统一可以使用selectKey、classKey产生主键。

  当然对于,update、delete同样适用当前方法。

具体写法参考:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<insert id="insertUserO" parameterClass="test.A">  
 
    INSERT INTO A
 
    (
 
      USER_NAME  ,
 
      USER_ID     ,
 
      PASSWORD  ,
 
      create_time 
 
    )
 
    values(
 
   #userName#,
 
    #userId#,
 
   #password#,
 
   SYSDATE
 
    );
 
    INSERT INTO SUBA
 
    (
 
        CNAME,
 
         USER_ID     ,
 
      FLAG     ,
 
      EMP_ID  
 
    )values(
 
    #cname#,
 
     #userId#,
 
    #flag#,
 
     P_GET_KEY('SEQ_USER_KEY')
 
)
</insert>

(注:本人文章均为原创,转载请注明出处!刀光剑影20110215写于深圳。)

posted on   刀光剑影  阅读(1610)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示