Mybatyis foreache 標(biāo)簽
在Mybatis的xml配置中使用集合,主要是用到了foreach動(dòng)態(tài)語(yǔ)句。
foreach的參數(shù):
foreach元素的屬性主要有 item,index,collection,open,separator,close。
item表示集合中每一個(gè)元素進(jìn)行迭代時(shí)的別名.
index指 定一個(gè)名字,用于表示在迭代過(guò)程中,每次迭代到的位置(不知道具體的用處).
open表示該語(yǔ)句以什么開始,separator表示在每次進(jìn)行迭代之間以什么符號(hào)作為分隔 符.
close表示以什么結(jié)束
問(wèn)題:
在使用mybatis中使用 foreach 出現(xiàn)如下問(wèn)題
org.apache.ibatis.reflection.ReflectionException:There is no getter for property named '__frch_item_0' in 'TestEntity'
foreach 代碼如下:
<foreach collection="companys" index="index" item="item" open=" (" close=") " separator=",">
#{item}
</foreach>
問(wèn)題分析:
這邊使用了一個(gè)第三方分頁(yè)插件
com.github.miemiedev.mybatis.paginator.domain.PageBounds;
查詢一:this.getSqlSession().selectList(toMybatisStatement("selectByConditions"), params, bounds);
查詢二:this.getSqlSession().selectList(toMybatisStatement("selectByConditions"), params);
使用第一種帶第三方分頁(yè)插件查詢 報(bào)錯(cuò):
org.apache.ibatis.reflection.ReflectionException:There is no getter for property named '__frch_item_0' in 'TestEntity'
使用第二種方式查詢 能夠正常使用。
解決方案
如果想要使用第一種查詢方式時(shí) 可以使用一下兩種解決方法:
解決方案1:parameterType 參數(shù)類型將 TestEntity 修改成 map
解決方案2:將 #{item} 修改成 ${item} 如果是字符串則修改成 '${item}'
mybatis 中 #{}與${}的區(qū)別
默認(rèn)情況下,使用#{}語(yǔ)法,MyBatis會(huì)產(chǎn)生PreparedStatement語(yǔ)句中,并且安全的設(shè)置PreparedStatement參數(shù),這個(gè)過(guò)程中MyBatis會(huì)進(jìn)行必要的安全檢查和轉(zhuǎn)義。
示例1:
執(zhí)行SQL:Select * from company where id = #{id}
參數(shù):id =>10
解析后執(zhí)行的SQL:Select * from emp where id= ?
執(zhí)行SQL:Select * from company where id= ${id }
參數(shù):id 傳入值為:10
解析后執(zhí)行的SQL:Select * from company where id=10
使用foreach循環(huán)的時(shí)候 companys 這邊傳入的是string 數(shù)組
使用foreach循環(huán)時(shí) 默認(rèn)會(huì) 將item 轉(zhuǎn)成 __frch_item_0 ...
1.我們使用#{} 獲取參數(shù) 則變成 __frch_item_0=>10... Select * from emp where id in(?,?,?)
2.我們使用${} 獲取參數(shù) 則變成 10 傳入數(shù)據(jù)中 .. Select * from emp where id in(10,20,30) 則可以直接使用
所以在使用分頁(yè)查詢的時(shí)候使用第二種解決方案是可行的。那是什么原因?qū)е铝耸褂?{}這種獲取參數(shù)數(shù)據(jù)的方式會(huì)錯(cuò),而當(dāng)使用map作為參數(shù)時(shí)#{}又是可用的。
分析數(shù)據(jù):在使用#{}獲取參數(shù)時(shí),mybatis會(huì)將獲取到的數(shù)據(jù)存入一個(gè)map中,
例如:
{id="10",param1 = "test",_fors_item_0=591,_fors_item_1=592 }
其中 低于param1為正常獲取 數(shù)據(jù),_fors_item_0,_fors_item_1為循環(huán)時(shí)獲取的數(shù)據(jù),
同時(shí)在map還會(huì)有其他的參數(shù),其中包括 傳入類型 parameterType所帶入的對(duì)象(TestEntity)。
可能性分析解析:
使用PageBounds 的時(shí)候會(huì)將mybaits 的數(shù)據(jù)嵌入在PageBounds里面,
個(gè)人分析在PageBounds 回填參數(shù)的時(shí)候做了類型的判斷,
判斷傳入的parameterType是否是map類型,如果是則從map中獲取數(shù)據(jù),如果不是則將map映射成TestEntity實(shí)體,然而在實(shí)體中不存在_fors_item_0屬性,所以就提示錯(cuò)誤:
org.apache.ibatis.reflection.ReflectionException:There is no getter for property named '__frch_item_0' in 'TestEntity'
總結(jié) :
使用${}方式會(huì)引發(fā)SQL注入的問(wèn)題、同時(shí)也會(huì)影響SQL語(yǔ)句的預(yù)編譯,所以從安全性和性能的角度出發(fā),能使用#{}的情況下就不要使用${},