mybatis對映檔案引數處理
單個引數:mybatis不會做特殊處理,
#{引數名/任意名}:取出引數值。儘管我們在介面中指定啦引數為ID,但在對映檔案中可以任意名,如兩端程式碼的id和anyID,測試結果如下
public Employee getEmpById(Integer id);
<select id="getEmpById"
resultType="com.mfg.mybatis.bean.Employee" databaseId="mysql">
select *from employee where id = #{anyID}
</select >
測試程式碼和結果如下:
@Test
public void test01() throws IOException {
// 1、獲取sqlSessionFactory物件
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
// 2、獲取sqlSession物件
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3、獲取介面的實現類物件
//會為介面自動的建立一個代理物件,代理物件去執行增刪改查方法
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpById(3);
System.out.println(mapper.getClass());
System.out.println(employee);
} finally {
openSession.close();
}
}
多個引數:mybatis會做特殊處理。
多個引數會被封裝成 一個map,形成如key:param1…paramN,或者引數的索引也可以
value:傳入的引數值
#{}就是從map中獲取指定的key的值;
如果依然按照單個引數的取法會出現異常:
org.apache.ibatis.binding.BindingException: Parameter ‘id’ not found. Available parameters are [1, 0, param1, param2]
錯誤操作:
public Employee getEmpByIdAndLastName(Integer id,String lastName);
<select id="getEmpByMap"
resultType="com.mfg.mybatis.bean.Employee">
select * from ${tableName} where id=${id} and
last_name=#{lastName}
</select>
/**
* 測試mapper引數
* @throws IOException
*/
@Test
public void Test04() throws IOException {
SqlSessionFactory sessionFactory=getSqlSessionFactory();
SqlSession sqlSession=sessionFactory.openSession();
try {
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpByIdAndLastName(3,"jerry");
System.out.println(employee);
}finally {
sqlSession.close();
}
}
報錯如下:找不到引數id 應該為1,0,param1…這種形式。
此時我們有兩種修改方式
1️⃣:修改對映檔案為引數改為param1,param2
<select id="getEmpByIdAndLastName"
resultType="com.mfg.mybatis.bean.Employee">
select * from employee where id = #{param1} and
last_name=#{param2}
</select>
但這種方式在引數多的時候,每個引數都有一個數字對應,此時推薦使用命名引數的形式
2️⃣:命名引數形式,明確指定封裝引數時map.key;此時多個引數會被封裝成一個map,其中就key就是我們自己命名的引數名
key:id,lastName
key:引數值
取值:#{我們自己的命名引數}
public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);
<select id="getEmpByMap"
resultType="com.mfg.mybatis.bean.Employee">
select * from ${tableName} where id=${id} and
last_name=#{lastName}
</select>
兩種測試都可以
POJO:如果多個引數正好是我們業務邏輯的資料模型,我們就可以直接傳pojo;
#{屬性名}:取出傳入的pojo的屬性值
public void addEmp(Employee employee);
public void updata (Employee employee);
Map:如果多個引數不是業務模型中的資料,沒有對應的pojo,不經常使用,為了方便,我們也可以傳入map
#{key}:取出map中對應的值
public Employee getEmpByMap(Map<String, Object> map);
<select id="getEmpByMap"
resultType="com.mfg.mybatis.bean.Employee">
select * from employee where id=${id} and
last_name=#{lastName}
</select>
/**
* 測試mapper引數(Map)
* @throws IOException
*/
@Test
public void Test05() throws IOException {
SqlSessionFactory sessionFactory=getSqlSessionFactory();
SqlSession sqlSession=sessionFactory.openSession();
try {
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Map<String, Object> map=new HashMap<String, Object>();
map.put("id", 3);
map.put("lastName", "Meng_FanGuang");
Employee employee = mapper.getEmpByMap(map);
System.out.println(employee);
}finally {
sqlSession.close();
}
}
TO:如果多個引數不是業務模型中的資料,但是經常要使用,推薦來編寫一個TO(Transfer Object)資料傳輸物件
Page{
int index;
int size;
}
特別注意:當傳入的是物件或者map以及和基本型別或者String混合的情況時,比如:
public Employee getEmp(Integer id,@Param("e")Employee emp);
id-->{param1} lastName-->#{param2.lastName}或者#{e.lastName}
Connection:當傳入的是集合時,比如有LIst,Set或者陣列。 也會特殊處理。也是把傳入的list或者陣列封裝在map中。key:Collection(index),如果是List還可以使用這個list ,陣列可以使用array
public Employee getEmpById(List<Integer> ids);
取值:取出第一個id的值: #{list[0]}
myBatis引數原始碼分析
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
//1、引數為null直接返回
if (args == null || paramCount == 0) {
return null;
//2、如果只有一個元素,並且沒有Param註解;args[0]:單個引數直接返回
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
//3、多個元素或者有Param標註
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
//4、遍歷names集合;{0=id, 1=lastName,2=2}
for (Map.Entry<Integer, String> entry : names.entrySet()) {
//names集合的value作為key; names集合的key又作為取值的參考args[0]:args【1,"Tom"】:
//eg:{id=args[0]:1,lastName=args[1]:Tom,2=args[2]}
param.put(entry.getValue(), args[entry.getKey()]);
// add generic param names (param1, param2, ...)param
//額外的將每一個引數也儲存到map中,使用新的key:param1...paramN
//效果:有Param註解可以#{指定的key},或者#{param1}
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
}
引數的兩種獲取方式 ##
#{}:可以獲取map中的值或者pojo物件屬性的值;
${}:可以獲取map中的值或者pojo物件屬性的值;
<select id="getEmpByIdAndLastName"
resultType="com.mfg.mybatis.bean.Employee">
select * from employee where id = ${id} and
last_name=#{lastName}
</select>
區別:
#{}:是以預編譯的形式,將引數設定到sql語句中;PreparedStatement;防止sql注入
${}:取出的值直接拼裝在sql語句中;會有安全問題;
大多情況下,我們去引數的值都應該去使用#{};
原生sql不支援佔位符的地方,我們就要使用後者來進行取值。比如分表;按照年份分表,或者排序
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}
#{}更豐富的用法:
{}:更豐富的用法:
規定引數的一些規則:
javaType、 jdbcType、 mode(儲存過程)、 numericScale、
resultMap、typeHandler、jdbcTypeName、 expression(未來準備支援的功能);
jdbcType通常需要在某種特定的條件下被設定:在我們資料為null的時候,有些資料庫可能不能識別mybatis對null的預設處理。比如Oracle(報錯);JdbcType OTHER:無效的型別;因為mybatis對所有的null都對映的是原生Jdbc的OTHER型別,oracle不能正確處理;mybatis與JDBC原生型別的轉換如下:
由於全域性配置中:jdbcTypeForNull=OTHER;oracle不支援;兩種辦法
①:通過#{}傳引數時,將null型別設定為jdbcType的other型別
#{email,jdbcType=OTHER};
②、在總配置檔案中加入下面設定
<setting name="jdbcTypeForNull" value="NULL"/>