`
xubindehao
  • 浏览: 240113 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

转载 DBA的wiki 感觉很有用

阅读更多

引起语句多版本的一个原因。下面做了一个测试来演示这种情况,线上很多库上都有类似的问题。

ibatis版本:2.3.0

oracle版本:10.2.0.4

 

1. 建临时表

create table tmp_jd_bind_test(id number, c1 number, c2 date);

2. java 端调用程序,用ibatis, 插入记录, 这一步是雷卷配合帮忙做的,非常感谢雷卷

<insert id="SkinDAO.insertCheck" parameterClass="java.util.Map">
insert into tmp_jd_bind_test(id, c1, c2) values(#id#, #c1#, #c2#)
</insert>

public void testCheck() throws Exception {
  Map<String, Object> params = new HashMap<String, Object>();
    params.put("id", 1);
    skinDAO.insertCheck(params);
    params.put("c1", 0);
    skinDAO.insertCheck(params);
    params.put("c2", new Date());
    skinDAO.insertCheck(params);
    params.remove("id");
    skinDAO.insertCheck(params);
    params.remove("c1");
    skinDAO.insertCheck(params);
}

3. 看表里的数据

SQL> select * from tmp_jd_bind_test;

ID C1 C2
---------- ---------- ------------
1
1 0
1 0 12-JAN-10
  0 12-JAN-10
    12-JAN-10


4. 找到刚才执行的insert语句的sql_id --sql_id: aq45j8c82fg6n

aq45j8c82fg6n
insert into tmp_jd_bind_test(id, c1, c2) values(:1, :2, :3)


5. 看这个sql_id的多个子游标

SQL> select sql_id, child_address, child_number from v$sql where sql_id = 'aq45j8c82fg6n';

SQL_ID CHILD_ADDRESS CHILD_NUMBER
------------- ---------------- ------------
aq45j8c82fg6n 00000000B57BAEF8 0
aq45j8c82fg6n 00000000A5D45A28 1
aq45j8c82fg6n 00000000A5ADAD48 2
aq45j8c82fg6n 00000000B57A29E8 3
aq45j8c82fg6n 00000000924298F0 4


6. 查看这些子游标的绑定变量情况

SQL> select * from v$sql_bind_metadata where address in ('00000000B57BAEF8', '00000000A5D45A28', '00000000A5ADAD48', '00000000B57A29E8', '00000000924298F0') order by position, address;

ADDRESS POSITION DATATYPE MAX_LENGTH ARRAY_LEN BIND_NAME
---------------- ---------- ---------- ---------- ---------- ------------------------------
00000000924298F0 1 1 32 0 1
00000000A5ADAD48 1 2 22 0 1
00000000A5D45A28 1 2 22 0 1
00000000B57A29E8 1 1 32 0 1
00000000B57BAEF8 1 2 22 0 1
00000000924298F0 2 1 32 0 2
00000000A5ADAD48 2 2 22 0 2
00000000A5D45A28 2 2 22 0 2
00000000B57A29E8 2 2 22 0 2
00000000B57BAEF8 2 1 32 0 2
00000000924298F0 3 180 11 0 3
00000000A5ADAD48 3 180 11 0 3
00000000A5D45A28 3 1 32 0 3
00000000B57A29E8 3 180 11 0 3
00000000B57BAEF8 3 1 32 0 3

15 rows selected.

7. 总结一下规律
如果表里字段是number型的,用ibatis传一个null进来,会绑定成varchar2类型的,
如果表里字段是date型的,用ibatis传一个null进来,也会绑定成varchar2类型的。

8. 怎么解决这个问题?

这是接下来要考虑问题。

<insert id="SkinDAO.insertCheck" parameterClass="java.util.Map">
  insert into tmp_jd_bind_test(id, c1, c2) values(#id#, #c1#, #c2#)
</insert>

这种写法容易导致多版本, 当传入的值为null时,ibatis不能判断出字段的类型

<insert id="SkinDAO.insertCheck" parameterClass="java.util.Map">
  insert into tmp_jd_bind_test(id, c1, c2) values(#id:BIGINT#, #c1:BIGINT#, #c2:DATE#)
</insert>
通过在sqlmap文件中指定每个字段的类型,不会产生由于类型不匹配引起的多版本
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics