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写于深圳。)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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,谁才是开发者新宠?