mybatis多个参数(不使用@param注解情况下),sql参数占位符正确写法
轉載自??mybatis多個參數(不使用@param注解情況下),sql參數占位符正確寫法
useActualParamName配置
| useActualParamName | 允許使用方法簽名中的名稱作為語句參數名稱。 為了使用該特性,你的工程必須采用Java 8編譯,并且加上-parameters選項。(從3.4.1開始) | true | false | true |
mybatis的全局配置useActualParamName決定了mapper中參數的寫法,默認為true
代碼展示:
@Test public void findUserById() {SqlSession sqlSession = getSessionFactory().openSession();UserDao userMapper = sqlSession.getMapper(UserDao.class);User user = userMapper.findUserById(1,"lpf");Assert.assertNotNull("沒找到數據", user); } public interface UserDao {User findUserById (int id,String name); }1.如果useActualParamName設置為true時
傳遞參數需要使用
#{arg0}-#{argn}或者#{param1}-#{paramn}
比如:
<select id="findUserById" resultType="com.lpf.entity.User" >select * from m_user where id = #{arg0} and name =#{arg1} </select>或者
<select id="findUserById" resultType="com.lpf.entity.User" >select * from m_user where id = #{param1} and name =#{param2} </select>2.如果useActualParamName設置為false時
傳遞參數需要使用
#{0}-#{n}或者#{param1}-#{paramn}
<select id="findUserById" resultType="com.lpf.entity.User" >select * from m_user where id = #{0} and name =#{1} </select>或者
<select id="findUserById" resultType="com.lpf.entity.User" >select * from m_user where id = #{param1} and name =#{param2} </select>下面是多個參數的錯誤寫法直接寫參數名(如果方法只有一個參數是可以用參數名代替的,其實如果只有一個參數,任何名稱都是可以的)
<select id="findUserById" resultType="com.lpf.entity.User" >select * from m_user where id = #{id} and name =#{name} </select>源碼解讀(3.4.6):
在mapper的代理對象調用方法時,最終會是MapperMethod對象的execute方法。如下:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 如果目標方法是Object類繼承來的,直接調用目標方法if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else if (isDefaultMethod(method)) {return invokeDefaultMethod(proxy, method, args);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}// 從緩存中獲取MapperMethod 對象,如果沒有就創建新的并添加final MapperMethod mapperMethod = cachedMapperMethod(method);// 執行sql 語句return mapperMethod.execute(sqlSession, args); }MapperMethod的一個內部類MethodSignature封裝了Mapper接口中定義的方法的相關信息。而MethodSignature的一個屬性ParamNameResolver對象處理接口中定義的方法的參數列表。
ParamNameResolver 的屬性
// 記錄參數在參數列表中的位置索引與參數名稱之間的對應關系 private final SortedMap<Integer, String> names;// 記錄對應的方法參數是否使用了@Param注解 private boolean hasParamAnnotation;ParamNameResolver的構造函數
/*** 通過反射讀取方法中的信息,并初始化上面兩個字段* @param config* @param method*/ public ParamNameResolver(Configuration config, Method method) {// 獲取參數列表中每個參數的類型final Class<?>[] paramTypes = method.getParameterTypes();// 獲取參數列表上的注解 @Paramfinal Annotation[][] paramAnnotations = method.getParameterAnnotations();// 該集合用于記錄參數索引與參數名稱的對應關系final SortedMap<Integer, String> map = new TreeMap<Integer, String>();int paramCount = paramAnnotations.length;// 遍歷所有參數for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {if (isSpecialParameter(paramTypes[paramIndex])) {// 如果參數是RowBounds類型或者ResultHandler類型,則跳過該參數continue;}String name = null;// 遍歷該參數上的注解集合for (Annotation annotation : paramAnnotations[paramIndex]) {if (annotation instanceof Param) {// 獲取@Param注解指定的參數名稱hasParamAnnotation = true;name = ((Param) annotation).value();break;}}// 沒有@Param注解的話 執行下面邏輯if (name == null) {// useActualParamName==true時 即name = arg0 ...if (config.isUseActualParamName()) {name = getActualParamName(method, paramIndex);}if (name == null) {//useActualParamName == false是 即 name="0" ...// use the parameter index as the name ("0", "1", ...)// 使用參數的索引作為其名稱name = String.valueOf(map.size());}}map.put(paramIndex, name);}names = Collections.unmodifiableSortedMap(map); }names集合主要是在ParamNameResolver.getNamedParams方法中使用
/**** @param args 用戶傳入的參數值列表* @return*/ public Object getNamedParams(Object[] args) {final int paramCount = names.size();if (args == null || paramCount == 0) {return null;} else if (!hasParamAnnotation && paramCount == 1) {// 未使用@Param注解且參數列表只有一個return args[names.firstKey()];//即args[0] 參數的值} else {// 下面是為參數創建param+索引的格式作為默認參數名稱 如:param1 下標從1開始final Map<String, Object> param = new ParamMap<Object>();int i = 0;for (Map.Entry<Integer, String> entry : names.entrySet()) {param.put(entry.getValue(), args[entry.getKey()]);// add generic param names (param1, param2, ...)final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);// ensure not to overwrite parameter named with @Paramif (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i++;}return param;} }總結:
1.如果接口方法有一個或多個參數,并且使用了@Param注解,sql語句中的參數用注解的value值,
2.如果接口方法的參數只有一個,并且沒有使用@Parma注解sql語句直接使用任何名稱均可。
3.如果接口的方法有多個參數,并且沒有使用@Parma注解,sql語句使用param1...paramn是不會錯的。
4.sql語句中的參數占位符名稱和接口方法的參數名稱沒有什么關系。
總結
以上是生活随笔為你收集整理的mybatis多个参数(不使用@param注解情况下),sql参数占位符正确写法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机大神们谈论他们是如何开始学习编程如
- 下一篇: mybatis源码阅读(五) ---执行