針對模糊查詢的三種方式
業務層傳遞數據,在映射文件取值時where語句理論上應寫為where user_name like #{user_name}%,但實際上控制台會報錯。
### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%' at line 1
提示的是數據庫Sql語句的錯誤,如果使用了log4j日志,控制台顯示:
DEBUG [main] - ==> Preparing: select * from web_user where user_name like ?%
DEBUG [main] - ==> Parameters: 悟(String)
后面會解釋為什么會出錯。所以直接取值是不行的,可以使用下面的幾種方式。
一 在業務層進行處理
在業務層接收到數據時,首先對數據進行一次簡單的處理操作。
//接口中的方法為List<User> where01(String user_name); //MyBatisUtil類詳見前面的MyBatis工具類整合 try { sqlSession = MyBatisUtil.getSqlSession(); String user_name = "悟"; List<User> list = sqlSession.getMapper(UserDao.class).where01(user_name + "%"); logger.debug(list); } finally { MyBatisUtil.closeSqlSession(sqlSession); }
映射文件中的sql語句為:
<select id="where01" resultType="self.exercise.bean.User" parameterType="string"> select * from web_user where user_name like #{user_name} </select>
此時日志在控制台輸出
DEBUG [main] - ==> Preparing: select * from web_user where user_name like ?
DEBUG [main] - ==> Parameters: 悟%(String)
二 在映射文件取值時進行處理
在業務層不進行數據處理,在映射文件中不用#{}取值,改為${}方式取值。
<select id="where01" resultType="self.exercise.bean.User" parameterType="string"> select * from web_user where user_name like '${_parameter}%' </select>
控制台的信息:
DEBUG [main] - ==> Preparing: select * from web_user where user_name like '悟%'
DEBUG [main] - ==> Parameters:
由此可以看出#和$的區別
#會將字符串進行預處理,用一對引號加在字符串外邊,再替代?如#{user_name}% -->'悟'%,所以直接用#{}接值控制台報錯的原因就在於此。
$將取到的數據直接替換掉,並不會進行預處理。如'${_parameter}%' -->'悟%'
三 在映射文件用方法進行拼接
在業務層不進行數據處理,在映射文件調用MySql的concat(param1,param2,...)進行拼接
<select id="where03" resultType="self.exercise.bean.User" parameterType="string"> select * from web_user where user_name like concat(#{user_name},"%") </select>
日志:
DEBUG [main] - ==> Preparing: select * from web_user where user_name like concat(?,"%")
DEBUG [main] - ==> Parameters: 悟(String)
針對多條件的where語句
當有多個查詢條件時,用if標簽進行條件篩選 如
//接口中的方法為List<User> wheremore(@Param("userName") String user_name, @Param("account") String account);
try { sqlSession = MyBatisUtil.getSqlSession(); String user_name = "悟"; String account = "wukong"; List<User> list = sqlSession.getMapper(UserDao.class).wheremore(user_name, account); logger.debug(list); } finally { MyBatisUtil.closeSqlSession(sqlSession); }
映射文件中的內容為:
<select id="wheremore" resultType="self.exercise.bean.User"> select * from web_user where 1=1 <if test="userName != null and userName != ''.trim()"> and user_name like concat(#{userName},"%") </if> <if test="account != null and account != ''.trim()"> and account = #{account} </if> </select>
其中,test中的變量對應的為map中的key值、類中的屬性名或者接口中param方法映射出的屬性名
但是之前提到過,XML中有些運算符不能被識別,所以test中進行測試時一些運算符需要進行用轉義運算符替換,XML中有五個轉義字符:
運算符 轉義字符
邏輯與 & &
大於號 > >
小於號 < <
雙引號 " "
單引號 ' '
在讀取的時候,解析器會自動將其轉換回"&","<",">"等特殊字符,正常來說,只有"<" 字符和"&"字符對於XML來說是嚴格禁止使用的。
需要注意的是:
a. 轉義序列各字符間不能有空格;
b. 轉義序列必須以";"結束;
c. 單獨的&不被認為是轉義開始;
d. 區分大小寫。
判斷一個字符串不為空串的幾種方式:
<if test="user_name != ''.trim()"></if> <if test="user_name.lengh() != 0"></if>
以上的多條件查詢方法,where后面跟着 1=1,每次執行sql語句都會進行一次判斷(即使條件全部為空),當數據量很大時效率低下,可以where標簽進行改進。
<select id="wheremore02" resultType="self.exercise.bean.User"> select * from web_user <where> <if test="userName != null and userName != ''.trim()"> and user_name like concat(#{userName},"%") </if>
<if test="account != null && account.length() != 0">
and account = #{account} </if> </where> </select>
where標簽會檢索語句,將where中的第一個and 或者or 去掉,這里的and 和or 都是sql中的關鍵字(注意關鍵字后的空格也會被去掉),如果名為and_user_name的屬性在最前面,則不會被檢索出來。
choose標簽,相當於Java中的switch分支語句,跟if標簽類似。
但是這種方式不能使用,當最前邊的條件判斷正確后,會直接break;后面的條件不再判斷。
<select id="wheremore03" resultType="self.exercise.bean.User"> select * from web_user <where> <choose> <when test="userName != null and userName != ''.trim()"> and user_name like concat(#{userName},"%") </when> <when test="account != null && account.length() != 0"> and account = #{account} </when> </choose> </where> </select>