問題:在Oracle數據庫中有兩個表其中一個表名與另外一個表名只相差了一個下劃線,在使用jdbc連接Oracle查詢有下劃線的表的表結構的時候就會將另外一個表的字段名帶出來,因此創建兩個表A_B_D和表A_BCD。
CREATE TABLE A_B_D(A1 NUMBER,A2 NUMBER,A3 CHAR);
CREATE TABLE A_BCD(A11 NUMBER,A12 CHAR,A13 FLOAT);
通過查看Oracle jdbc源碼發現
通過使用like查詢發現問題復現。
SELECT * FROM all_tab_columns WHERE table_name LIKE 'A_B_D' ORDER BY table_name,COLUMN_id
分析: rs = oracle.getMetaData().getColumns(null, table.getTableSchema(), table.getTableName(), null);
while (rs.next()) {
col = new Column(rs);
columns.add(col);
}
-
getColumns
<pre><code class="language-html hljs xml"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">ResultSet getColumns(String catalog,</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> String schemaPattern,</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> String tableNamePattern,</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> String columnNamePattern)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> throws SQLException</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre> </li>
Oracle getColumns查詢表時用的是like,模糊查詢,傳入的表名是一個模板的樣式,在Oracle中下劃線(_)和百分號(%)都是代表的任意的一個字符,因此此時傳入的表名爲A_B_D,就會將表A_BCD的字段和表A_B_D的字段全部查出來。
解決方法:通過轉義將下劃線轉義爲特殊字符
sql語句中通過使用escape在下劃線等通配符前自定義一個轉義字符(通常使用:\,當然可以自定義其他字符),這樣通配符就會解釋爲普通的字符。
SELECT * FROM all_tab_columns WHERE table_name LIKE 'A_B\_D' ESCAPE'\' ORDER BY table_name,COLUMN_id
在jdbc獲取字段名中則將"_"用"\_"代替就可以
String tablename = table.getTableName();
tablename = tablename.replace("_","\_");
rs = oracle.getMetaData().getColumns(null, table.getTableSchema(), tablename, null);
這樣就將下劃線轉義爲了特殊字符,查A_B_D時就會只將這個表的字段查出來,問題解決。
對比PG,PG將下劃線轉義爲特殊字符爲"//_"