在使用Mybatis過程中,你可以體會到它的強大與靈活之處,由衷的為Mybatis之父點上999個贊!在使用過程中經常會遇到這樣一種情況,我查詢數據的時候,表名稱是動態的從程序中傳入的,比如我們通過mybatis的xml文件寫sql查詢時都是下面的樣子:
1、正常的查詢
1
2
3
|
<select
id="activityEnrollModelTableName" parameterType="java.util.HashMap" resultType="java.util.HashMap">
SELECT * FROM user WHERE userid =
|
上面的查詢語句用mybatis執行時,其實是自動的按照JDBC的預編譯語句方式執行的,等同於下面一段JDBC代碼的執行過程
1
2
3
4
5
6
7
8
9
|
Class.forName(
"com.mysql.jdbc.Driver");
Connection conn = DriverManage.getConnection(
"jdbc:mysql://localhost:3306/dbname","root","112233");
PreparedStatement preState = conn.prepareStatement(
"SELECT * FROM user WHERE userid = ?");
preState.setString(
1,"96");
ResultSet result = preState.executeQuery();
while(result.next()){
result.getString(columnname);
..........
}
|
到這里我們不禁疑惑,難道mybatis默認都是按照預編譯語句的方式執行sql的嗎?其實就是這樣。通過查看mybatis官網文檔可以看到有這么一個參數,statementType=[STATEMENT | PREPARED | CALLABLE ];有三個可選值,mybatis默認值是PREPARED;
這個參數是什么作用呢:
- 設定mybatis執行sql的模式
- STATEMENT設定為非預編譯語句模式
- PREPARED設定為預編譯語句模式–mybatis默認
- CALLABLE設定為兼容模式,或者自適應模式,比如設置該值后,mybatis處理sql時會自動的處理根據#、$去判斷處理,后面說一下#和$的區別。
綜上所述,mybatis默認按照預編譯語句方式執行sql語句
2、動態傳入表名
其實也經常會遇到動態的傳入tableName的情況,也就是說上面的sql語句中的”user”是動態傳入的,動態傳入表名是mybatis中的一種特殊情況,
1
2
3
|
<select
id="activityEnrollModelTableName" parameterType="java.util.HashMap" resultType="java.util.HashMap">
SELECT * FROM
|
針對上面的語句,如果讓mybatis仍然按照預編譯語句方式執行時,等同於如下面的JDBC代碼:
1
2
3
4
5
6
7
8
9
10
|
Class.forName(
"com.mysql.jdbc.Driver");
Connection conn = DriverManage.getConnection(
"jdbc:mysql://localhost:3306/dbname","root","112233");
PreparedStatement preState = conn.prepareStatement(
"SELECT * FROM ? WHERE userid = ?");
preState.setString(
1,"USER");
preState.setString(
2,"96");
ResultSet result = preState.executeQuery();
while(result.next()){
result.getString(columnname);
..........
}
|
我們把該段JDBC代碼通過java代碼執行后,發現會報異常:
1
|
java.sql.SQLException: ORA-00903: 表名無效
|
所以可以說明預編譯語句不能用於列名(查詢的列名也不能用預編譯語句)、表名;只能作用與where條件參數屬性!既然JDBC就不能將預編譯語句方式作用與表名上面,那么mybatis就同樣也行不通(因為mybatis默認是預編譯語句模式)。不過mybatis也早已考慮到了這種情況,所以為我們做了處理:
- select標簽語句中添加statementType=”STATEMENT”的屬性配置
- 標簽內的sql語句中將所有的${}更換成為#{},即將$還成#;
123<select id= "activityEnrollModelTableName" statementType="STATEMENT" parameterType="java.util.HashMap" resultType="java.util.HashMap">SELECT * FROM $ WHERE userid = $ / /正確的寫法</select>
上面的語句標簽中通過添加statementType=”STATEMENT”配置后,mybatis就不再使用預編譯語句方式執行sql語句了,也就是通過直接執行sql語句操作;那么既然添加了statementType=”STATEMENT”非預編譯配置后,為什么還需要把#換成$呢?其實是這樣:
- “#” 是預編譯語句模式下面的默認匹配符,也就是說mybatis遇到#{}時,將#替換成占位符?;被解析為一個JDBC預編譯語句,然后再將#本身的值set進來。
- “$” 是非預編譯語句下面的匹配符,非預編譯語句說白了就是你傳入什么sql語句,就執行什么sql語句,mybatis不做任何處理操作,但是這里mybatis會將${}對應的值,當做一個字符串處理,也就是說你程序接口方法中傳遞過來參數值是什么,對應的sql填充就是什么!