MyBatis參數獲取和傳遞

1、參數獲取方式

MyBatis可以通過以下兩種方式獲取參數值:

  • #{變量名}
    本質是占位符賦值

  • ${變量名}

    本質是字符串拼接,如果拼接的是字符串類型或日期類型,則需要手動添加單引號

2、參數獲取的幾種情況:

2.1 mapper接口方法的參數為單個字面量類型

可以通過${}#{}以任意名稱獲取變量值,需注意${}的單引號問題

如下:

    public interface UserMapper {User selectUserByUserName(String username);}
    <select id="selectUserByUserName" resultType="User"><!-- select * from t_user where username = '${username}' -->select * from t_user where username = #{username}</select>
2.2 mapper接口方法的參數為多個時

mybatis會將多個參數封裝到map集合中,并以兩種方式存儲:

  • 方式一:以arg0,arg1,arg2,…為鍵,以參數為值
  • 方式二:以param1,param2,param3,…為鍵,以參數為值

可以通過#{}${}兩種方式以鍵的方式獲取值即可,需注意${}的單引號問題

如下:

    List<User> selectUserByUserNameAndAge(String username, Integer age, String sex);
    <select id="selectUserByUserNameAndAge" resultType="User"><!-- select * from t_user where username = '${arg0}' and age = ${arg1} and sex = '${arg2}' -->select * from t_user where username = #{arg0} and age = #{arg1} and sex = #{arg2}</select>
2.3 mapper接口方法有多個參數時,手動封裝map參數

可以通過#{}${}兩種方式以鍵的方式獲取值即可,需注意${}的單引號問題

如下:

    @Testpublic void testQueryByMapParam(){SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);Map<String, Object> map = new HashMap<>();map.put("username", "李斯");map.put("age", 23);map.put("sex", "女");List<User> admin = userMapper.selectUserByMap(map);admin.stream().forEach(System.out::println);}
    List<User> selectUserByMap(Map<String, Object> map);
    <select id="selectUserByMap" resultType="User">select * from t_user where username = #{username} and age = #{age} and sex = #{sex}</select>
2.4 mapper接口方法的參數為實體類類型的參數

可以通過${}#{}以任意名稱獲取變量值,需注意${}的單引號問題

如下:

    @Testpublic void testInsertUser(){SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);User user = new User();user.setUsername("中華");user.setPassword("123456");user.setAge(32);user.setSex("男");int i = userMapper.insertUser(user);System.out.println(i);}
    int insertUser(User user);
    <insert id="insertUser">insert into t_user values(null, #{username}, #{password}, #{age}, #{sex})</insert>
2.5 使用@Param注解命名參數

mybatis會將多個參數封裝到map集合中,并以兩種方式存儲:

  • 方式一:以@Param注解的值為鍵,以參數為值
  • 方式二:以param1,param2,param3,…為鍵,以參數為值
    因此可以通過${}#{}以任意名稱獲取變量值,需注意${}的單引號問題
    @Testpublic void testQueryByParam(){SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<User> admin = userMapper.selectUserByParam("李斯", 23, "女");admin.stream().forEach(System.out::println);}
    List<User> selectUserByParam(@Param("username") String username, @Param("age") Integer age, @Param("sex") String sex);
    <select id="selectUserByParam" resultType="User">select * from t_user where username = #{username} and age = #{age} and sex = #{sex}</select>

3、MyBatis參數解析原理:

3.1 參數封裝

主要分析MyBatis對接口參數的處理,如參數的封裝、參數值的獲取原理。

org.apache.ibatis.reflection.ParamNameResolver#ParamNameResolverorg.apache.ibatis.reflection.ParamNameResolver#getNamedParams
  • ParamNameResolver構造
    構造方法中處理方法參數的映射,建立參數的索引和參數名的映射關系。
    // 參數名稱處理public ParamNameResolver(Configuration config, Method method) {// 是否使用真實的參數名,默認為truethis.useActualParamName = config.isUseActualParamName();// 獲取方法的參數類型數組final Class<?>[] paramTypes = method.getParameterTypes();// 獲取方法參數注解final Annotation[][] paramAnnotations = method.getParameterAnnotations();// 存儲參數信息臨時對象final SortedMap<Integer, String> map = new TreeMap<>();int paramCount = paramAnnotations.length;// get names from @Param annotationsfor (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {/**The key is the index and the value is the name of the parameter. The name is obtained from Param if specified. When Param is not specified, the parameter index is used. Note that this index could be different from the actual index when the method has special parameters (i.e. RowBounds or ResultHandler).aMethod(@Param("M") int a, @Param("N") int b) -> {{0, "M"}, {1, "N"}}aMethod(int a, int b) -> {{0, "0"}, {1, "1"}}aMethod(int a, RowBounds rb, int b) -> {{0, "0"}, {2, "1"}}*/if (isSpecialParameter(paramTypes[paramIndex])) {// 跳過特殊參數 ,如RowBounds 或 ResultHandlercontinue;}String name = null;for (Annotation annotation : paramAnnotations[paramIndex]) {if (annotation instanceof Param) {// 當前參數存在@Param注解時,參數名設置為注解的value值hasParamAnnotation = true;name = ((Param) annotation).value();break;}}if (name == null) {// 如果存在@Param注解,且沒有指定參數名if (useActualParamName) {// 取出方法參數名,如果時單一普通參數,則返回arg0name = getActualParamName(method, paramIndex);}if (name == null) {// use the parameter index as the name ("0", "1", ...)// gcode issue #71// 此時,將索引作為參數名name = String.valueOf(map.size());}}map.put(paramIndex, name);}names = Collections.unmodifiableSortedMap(map);}
  • getNamedParams

建立參數名和參數值的映射關系,并返回參數值

      /*** <p>* A single non-special parameter is returned without a name. Multiple parameters are named using the naming rule. In* addition to the default names, this method also adds the generic names (param1, param2, ...).* </p>** @param args*          the args** @return the named params*/public Object getNamedParams(Object[] args) {final int paramCount = names.size();if (args == null || paramCount == 0) {return null;}// 單一參數,且沒有@Param注解時if (!hasParamAnnotation && paramCount == 1) {Object value = args[names.firstKey()];// 此處會對集合類型的參數進行包裝處理return wrapToMapIfCollection(value, useActualParamName ? names.get(names.firstKey()) : null);} else {// 建立參數名和值的映射,key:參數名 value:參數值final Map<String, Object> param = new ParamMap<>();int i = 0;for (Map.Entry<Integer, String> entry : names.entrySet()) {// 1.添加命名參數和參數值的映射關系param.put(entry.getValue(), args[entry.getKey()]);// add generic param names (param1, param2, ...)final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);// ensure not to overwrite parameter named with @Paramif (!names.containsValue(genericParamName)) {// 2.同時添加一個以param1,param2...為參數名 和 參數值的映射關系param.put(genericParamName, args[entry.getKey()]);}i++;}return param;}}

wrapToMapIfCollection

      /*** Wrap to a {@link ParamMap} if object is {@link Collection} or array.** @param object*          a parameter object* @param actualParamName*          an actual parameter name (If specify a name, set an object to {@link ParamMap} with specified name)** @return a {@link ParamMap}** @since 3.5.5*/public static Object wrapToMapIfCollection(Object object, String actualParamName) {// 如果是集合類型,則包裝key為collection、list的map返回if (object instanceof Collection) {ParamMap<Object> map = new ParamMap<>();map.put("collection", object);if (object instanceof List) {map.put("list", object);}Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));return map;}// 如果是數據組類型,則包裝key為array的map返回if (object != null && object.getClass().isArray()) {ParamMap<Object> map = new ParamMap<>();map.put("array", object);Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));return map;}// 如果不是集合類型或數組類型,則直接返回當前值return object;}
3.2 參數調用

在org.apache.ibatis.binding.MapperMethod#execute方法中,通過convertArgsToSqlCommandParam獲取參數值。

    public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result = executeForCursor(sqlSession, args);} else {// 獲取參數值Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) {result = Optional.ofNullable(result);}}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + command.getName());}if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {throw new BindingException("Mapper method '" + command.getName()+ "' attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");}return result;}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/211372.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211372.shtml
英文地址,請注明出處:http://en.pswp.cn/news/211372.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

判斷一個Series序列的值是否為單調遞減Series.is_monotonic_decreasing

【小白從小學Python、C、Java】 【計算機等考500強證書考研】 【Python-數據分析】 判斷一個Series序列中 各值是否單調遞減 s.is_monotonic_decreasing [太陽]選擇題 以下代碼的輸出結果中正確的是? import pandas as pd s1 pd.Series([3,2,1]) s2 pd.Series([3,2,4]) pri…

【代碼隨想錄】算法訓練計劃41

dp 1、343. 整數拆分 題目&#xff1a; 給定一個正整數 n &#xff0c;將其拆分為 k 個 正整數 的和&#xff08; k > 2 &#xff09;&#xff0c;并使這些整數的乘積最大化。 返回 你可以獲得的最大乘積 。 輸入: n 10 輸出: 36 解釋: 10 3 3 4, 3 3 4 36。 思路…

Kotlin Flow 操作符

前言 Kotlin 擁有函數式編程的能力&#xff0c;使用Kotlin開發&#xff0c;可以簡化開發代碼&#xff0c;層次清晰&#xff0c;利于閱讀。 然而Kotlin擁有操作符很多&#xff0c;其中就包括了flow。Kotlin Flow 如此受歡迎大部分歸功于其豐富、簡潔的操作符&#xff0c;巧妙使…

【矩陣論】Chapter 7—Hermite矩陣與正定矩陣知識點總結復習

文章目錄 1 Hermite矩陣2 Hermite二次型3 Hermite正定&#xff08;非負定矩陣&#xff09;4 矩陣不等式 1 Hermite矩陣 定義 設 A A A為 n n n階方陣&#xff0c;如果稱 A A A為Hermite矩陣&#xff0c;則需滿足 A H A A^HA AHA&#xff0c;其中 A H A^H AH表示 A A A的共軛轉…

數據結構入門————樹(C語言/零基礎/小白/新手+模擬實現+例題講解)

目錄 1. 樹的概念及其結構 1.1 樹的概念&#xff1a; 1.2 樹的相關概念&#xff1a; 1.3 樹的表示方法&#xff1a; ?編輯 1.4 樹的應用&#xff1a; 2. 二叉樹的概念及其結構 2.1 概念: 2.2 特點&#xff1a; 2.3 特殊二叉樹&#xff1a; 2.4 二叉樹的性質&#xf…

【深度學習】注意力機制(一)

本文介紹一些注意力機制的實現&#xff0c;包括SE/ECA/GE/A2-Net/GC/CBAM。 目錄 一、SE&#xff08;Squeeze-and-Excitation&#xff09; 二、ECA&#xff08;Efficient Channel Attention&#xff09; 三、GE&#xff08;Gather-Excite&#xff09; 四、A2-Net(Double A…

二維碼智慧門牌管理系統升級解決方案:數字鑒權

文章目錄 前言一、數字鑒權的核心機制二、數字鑒權的意義和應用 前言 隨著科技的飛速發展&#xff0c;我們的生活逐漸進入數字化時代。在這個數字化的過程中&#xff0c;數據的安全性和門牌信息的保障變得至關重要。今天&#xff0c;我們要介紹的是二維碼智慧門牌管理系統升級…

【論文復現】zoedepth踩坑

注意模型IO&#xff1a; 保證輸入、輸出精度、類型與復現目標一致。 模型推理的代碼 from torchvision import transforms def image_to_tensor(img_path, unsqueezeTrue):rgb transforms.ToTensor()(Image.open(img_path))if unsqueeze:rgb rgb.unsqueeze(0)return rgbdef…

dockerdesktop 導出鏡像,導入鏡像

總體思路 備份時 容器 > 鏡像 > 本地文件 恢復時 本地文件 > 鏡像 > 容器 備份步驟 首先,把容器生成為鏡像 docker commit [容器名稱] [鏡像名稱] 示例 docker commit nginx mynginx然后,把鏡像備份為本地文件,如果使用的是Docker Desktop,打包備份的文件會自動存…

機器學習筆記 - 基于C# + .net framework 4.8的ONNX Runtime進行分類推理

該示例是從官方抄的,演示了如何使用 Onnx Runtime C# API 運行預訓練的 ResNet50 v2 ONNX 模型。 我這里的環境基于.net framework 4.8的一個winform項目,主要依賴下面版本的相關庫。 Microsoft.Bcl.Numerics.8.0.0 Microsoft.ML.OnnxRuntime.Gpu.1.16.3 SixLabors.ImageShar…

MyString:string類的模擬實現 1

MyString&#xff1a;string類的模擬實現 前言&#xff1a; 為了區分標準庫中的string&#xff0c;避免編譯沖突&#xff0c;使用命名空間 MyString。 namespace MyString {class string{private:char* _str;size_t _size;size_t _capacity;const static size_t npos -1;// C標…

2023年 - 我的程序員之旅和成長故事

2023年 - 我的程序員之旅和成長故事 &#x1f525; 1.前言 大家好&#xff0c;我是Leo哥&#x1fae3;&#x1fae3;&#x1fae3;&#xff0c;今天咱們不聊技術&#xff0c;聊聊我自己&#xff0c;聊聊我從2023年年初到現在的一些經歷和故事&#xff0c;我也很愿意我的故事分…

TS學習——快速入門

TypeScript簡介 TypeScript是JavaScript的超集。它對JS進行了擴展&#xff0c;向JS中引入了類型的概念&#xff0c;并添加了許多新的特性。TS代碼需要通過編譯器編譯為JS&#xff0c;然后再交由JS解析器執行。TS完全兼容JS&#xff0c;換言之&#xff0c;任何的JS代碼都可以直…

Android 樣式小結

關于作者&#xff1a;CSDN內容合伙人、技術專家&#xff0c; 從零開始做日活千萬級APP。 專注于分享各領域原創系列文章 &#xff0c;擅長java后端、移動開發、商業變現、人工智能等&#xff0c;希望大家多多支持。 目錄 一、導讀二、概覽三、使用3.1 創建并應用樣式3.2 創建并…

DJI ONBOARD SDK—— 基礎控制功能 Joystick的講解,使用和擴展

DJI ONBOARD SDK/DJI OSDK ROS—— 基礎控制功能 Joystick的使用 概述 使用OSDK/OSDK_ROS 的無人機飛行控制功能&#xff0c;能夠設置并獲取無人機各項基礎參數&#xff0c;控制無人機執行基礎飛行動作&#xff0c;通過Joystick 功能控制無人機執行復雜的飛行動作。 Joystic…

【精彩回顧】恒拓高科亮相第十一屆深圳軍博會

2023年12月6日-8日&#xff0c;由中國和平利用軍工技術協會、全國工商聯科技裝備業商會、深圳市國防科技工業協會等單位主辦以及政府相關部門支持&#xff0c;深圳企發展覽有限公司承的“2023第11屆中國&#xff08;深圳&#xff09;軍民兩用科技裝備博覽會&#xff08;深圳軍博…

02 CSS基礎入門

文章目錄 一、CSS介紹1. 簡介2. 相關網站3. HTML引入方式 二、選擇器1. 標簽選擇器2. 類選擇器3. ID選擇器4. 群組選擇器 四、樣式1. 字體樣式2. 文本樣式3. 邊框樣式4. 表格樣式 五、模型和布局1. 盒子模型2. 網頁布局 一、CSS介紹 1. 簡介 CSS主要用于控制網頁的外觀&#…

C#如何使用SqlSugar操作MySQL/SQL Server數據庫

一. SqlSugar 連接MySQL數據庫 public class MySqlCNHelper : Singleton<MySqlCNHelper>{public static SqlSugarClient CnDB;public void InitDB() {//--------------------MySQL--------------------CnDB new SqlSugarClient(new ConnectionConfig(){ConnectionString…

窮舉問題-搬磚(for循環)

某工地需要搬運磚塊&#xff0c;已知男人一人搬3塊&#xff0c;女人一人搬2塊&#xff0c;小孩兩人搬1塊。如果想用n人正好搬n塊磚&#xff0c;問有多少種搬法&#xff1f; 輸入格式: 輸入在一行中給出一個正整數n。 輸出格式: 輸出在每一行顯示一種方案&#xff0c;按照&q…

玩轉大數據12:大數據安全與隱私保護策略

1. 引言 大數據的快速發展&#xff0c;為各行各業帶來了巨大的變革&#xff0c;也帶來了新的安全和隱私挑戰。大數據系統通常處理大量敏感數據&#xff0c;包括個人身份信息、財務信息、健康信息等。如果這些數據被泄露或濫用&#xff0c;可能會對個人、企業和社會造成嚴重的損…