Mybatis 中xml和註解映射,原來如此簡單

2021-01-08 田維常

MyBatis

提供了XML配置和註解配置兩種方式。今天就來搞搞這兩種方式是如何實現的。

的真正強大在於它的語句映射,這是它的魔力所在。由於它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的JDBC 代碼進行對比,你會立即發現省掉了將近 95% 的代碼。 致力於減少使用成本,讓用戶能更專注於 SQL 代碼。

來自官網。

Mybatis

映射九個頂級元素:

mapper:映射文件的根節點,只有一個屬性namespace(命名空間),作用如下:用於區分不同的mapper,全局唯一。綁定DAO接口,即面向接口編程,當綁定一個接口,就不用寫此接口的實現類,會通過接口的完全限定名找到對應的mapper配置來執行語句,所以,namespace的命名必須要寫接口的完全限定名。cache:配置給定命名空間的緩存。cache-ref:從其他命名空間引用緩存配置。resultMap:用來描述資料庫結果集和對象的對應關係。sql:可以重用的塊,也可以被其他語句引用。通常時存放一些公用性的。insert:映射插入語句。update:更新映射語句。delete:刪除映射語句。select:映射查詢語句。

xml方式

九個頂級映射元素對應標籤:

<mapper namespace="com.tian.mybatis.mapper.UserMapper"> <resultMap id="" type=""></resultMap> <sql id=""></sql> <cache blocking="" ></cache> <cache-ref namespace=""></cache-ref> <select id="selectUserById"></select> <insert id="insert" ></insert> <update id=""></update> <delete id=""></delete></mapper>

select詳解

可以看得出,後面可選項還是蠻多的。下面是官網對每項的解釋。

select使用案例

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.tian.mybatis.mapper.UserMapper"> <select id="selectUserById" resultType="com.tian.mybatis.entity.User" parameterType="int" > select * from m_user where id = #{id} </select></mapper>

id必須在這個Mapper中是唯一的,可以被用來引用這條語句 ,這個id必須與只對應的是XxxMapper.java中的方法,必須是一一對應。返回類型:User類型,resultType:查詢語句返回結果類型的完全限定名或別名。別名使用方式和parameterType是一樣的。參數:整形,表示查詢語句傳入參數的類型和完全限定名或別名。支持基礎數據類型和複雜數據類型。#{參數名}:告訴

生成的

PreparedStatement

參數,相對於

JDBC中

,改參數被標識為『?』。

別名與參數映射類型如下:

返回類型中別名的使用,注意:

如果是我們的entity類,那麼

是無法使用別名的,只能使用

才可以使用別名。

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.tian.mybatis.mapper.UserMapper"> <resultMap id="User" type="com.tian.mybatis.entity.User"/> <select id="selectUserById" resultMap="User" parameterType="int" > select * from m_user where id = #{id} </select></mapper>

但是如果使用的上面映射表裡,也可以直接使用別名。

資料庫裡有兩條數據:

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.tian.mybatis.mapper.UserMapper"> <select id="countUser" resultType="int"> select count(1) from m_user </select></mapper>

UserMapper.java

import com.tian.mybatis.entity.User;public interface UserMapper { int countUser();}

測試類:

public class MybatisApplication { public static final String URL = "jdbc:mysql://localhost.com:3306/mblog?useUnicode=true"; public static final String USER = "root"; public static final String PASSWORD = "123456"; public static void main(String[] args) { String resource = "mybatis-config.xml"; InputStream inputStream = null; SqlSession sqlSession = null; try { inputStream = Resources.getResourceAsStream(resource); //工廠模式 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //獲取sql操作會話 sqlSession = sqlSessionFactory.openSession(); //構造對象(這裡比較特殊,這裡構造對象的方式後面會專門分享) UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //查詢統計 System.out.println(userMapper.countUser()); } catch (Exception e) { e.printStackTrace(); } finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } sqlSession.close(); } }}

輸出:2

當資料庫表中的欄位名和我們entity中的欄位名不一致,怎麼處理?

在實際開發中,這種常見是在所難免。我們可以使用下面的這種方式解決。

實體類User

public class User { private Integer id; private String userName; private Integer age; //set get toString方法這裡就不貼了}

文件內容:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.tian.mybatis.mapper.UserMapper"> <resultMap id="User" type="com.tian.mybatis.entity.User"> <id column="id" property="id"/> <result column="name" property="userName"/> </resultMap> <select id="selectUserById" resultMap="User" parameterType="int" > select * from m_user where id = #{id} </select></mapper>

type:對應的是我們的實體類,全路徑名。id:可以理解為別名。

id:唯一標識,此id值用於select元素屬性的引用。column:對應我們資料庫表中的欄位名稱。property:對應我們的實體類的屬性,比如:User中的屬性userName,要和資料庫表m_user中的name對應。result:標識一些簡單屬性,其中column屬性代表資料庫的欄位名,property代表查詢出來的欄位名映射到實體類的某個屬性。繼續使用我們前面的測試類進行測試:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);System.out.println(userMapper.selectUserById(1));

輸出:

User{id=1, userName='tian', age=22}

注意:實體類的get set和toString()方法這裡給省略, 希望大家在使用的使用,使用快捷鍵很簡單的就搞定了。

上面提到過

,那麼他們兩到底有什麼區別呢?

resultType和resultMap 有什麼區別?

:直接表示返回類型, 包括基本數據類型和複雜數據類型。:外部定義的引用,通過對應的外部的id,表示結果映射到哪個上,一般用於欄位名和屬性名不一致的情況,或者需要做複雜的聯合查詢以便自由控制映射結果。兩者的關聯

當進行查詢時,查詢出來的每個欄位都會放在一個Map裡,當查詢元素返回屬性是

的時候,會將鍵值對取出賦所指定的屬性。其實

的每個查詢映射的返回類型都是

,只是當我們使用

的時候,會自動把對應的值賦給所指定的對象屬性,當使用

時候,因為map不是很好的表示領域,我們就進一步的轉化為對應的實體對象。

主要作用於複雜的聯合查詢上。

的自動映射級別:默認級別為PARTIAL,也可以在settings更改值。

注意:和本質是一樣的,都是Map數據結構,但是二者不能同時存在。

增刪改案例

insert

從這裡可以知道,關於增加insert是沒有返回值類型可以讓我們指定的。默認返回int類型。

<insert id="insert" parameterType="com.tian.mybatis.entity.User"> INSERT INTO m_user(`name`,age) VALUES ( #{userName},#{age})</insert>

對應Mapper中的方法

int insert(User user);

另外的update和delete類似,這裡就沒有必要逐一演示了。

註解方式

九個頂級映射元素對應註解:

其他部分註解是配合九個註解進行使用的。

select註解

把本地的UserMapper.xml刪掉,然後改一下

mybatis-config.xml

,把其中的UserMapper.xml給注釋掉。添加

<mapper/>

UserMapper.java添加註解

public interface UserMapper { @Select("select * from m_user where id = #{id}") User selectUserById(Integer id);}

再次測試

User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1);System.out.println(user);

User{id=1, userName='null', age=22}

從輸出內容看到,userName為null,這也是因為和資料庫表匯中的欄位name不一致導致的,那麼如何處理呢?

這麼搞,再添加一個註解:

public interface UserMapper { @Select("select * from m_user where id = #{id}") @Results( @Result(column = "name",property = "userName")) User selectUserById(Integer id);}

這樣也就是在使用註解的時候,處理實體屬性名和資料庫表欄位名不一樣的問題的辦法。

insert、update、delete同樣也可以使用註解來搞定了。

@Insert、@Update、@Delete配上相應的SQL語句。

註解和xml是否可以共存?

<update id="updateAuthorIfNecessary"> update m_user <trim prefix="SET" suffixOverrides=","> <if test="userName != null and userName != ''"> `name` = #{userName}, </if> <if test="gender != null and gender != 0"> gender = #{gender}, </if> <if test="age != null and age != 0"> age = #{age}, </if> </trim> where id=#{id} </update>

同時在UserMapper.java中的方法上添加註解

@Update("update m_user set `name` = #{userName},gender = #{gender},age = #{age} where id=#{id}")int updateAuthorIfNecessary(User user);

再次中子星的時候回報異常的:

nested exception is java.lang.IllegalArgumentException:Mapped Statements collection already contains value for com.tian.mybatis.mapper.UserMapper.updateAuthorIfNecessary. please check file [D:\workspace\my_code\mybatis\target\classes\mapper\UserMapper.xml] and com/tian/mybatis/mapper/UserMapper.java (best guess)

大致意思就是說,已經存在了,即就是不能同時使用xml和註解。二者選其一。

xml可以喝註解結合使用,但是得保證同一個方法不能同時存在xml和註解。

建議

簡單的sql處理可以使用註解,複雜的sql使用xml。但是實際工作還得看你待的項目中有沒有對這個進行規範化。

在項目中無非就三種:

1.全部必須使用xml方式。

2.全部必須使用註解方式。

3.可以同時使用xml和註解。

高級映射

association

映射到

JavaBean

的某個複雜的」數據類型」屬性,僅處理一對一的關聯關係。

<resultMap type="com.tian.mybatis.entity.User" id="userMapRole"> <id column="id" property="id" /> <result column="name" property="userName" /> <result column="age" property="age" /> <association property="role" javaType="UserRole"> <id column="id" property="id" /> <result column="roleName" property="roleName" /> </association></resultMap>

association的屬性節點:

property:映射資料庫列的實體對象屬性名。javaType:完整的java類名和限定名。propert所映射的屬性的類型。子元素

id:一般為映射主鍵,可以提高性能。result:column:映射的資料庫的欄位名。property:映射的數據列對應的實體對象屬性。collection

映射到JavaBean的某個複雜的」數據類型」屬性,這個屬性是一個集合列表,處理一對多的關聯關係。

<resultMap type="com.tian.mybatis.entity.User" id="userMapAddress"> <id column="id" property="id"/> <result column="name" property="userName"/> <collection property="lists" ofType="UserAddress"> <id column = "id" property = "id"> <result column="addressDesc" property="addressDesc"/> </collection> </resultMap>

ofType

:完整的Java類名和限定名。propert所映射的屬性的類型。

其餘和association基本一致。

association和collection都具備延遲加載功能。

延遲加載:先從單表查詢,需要時再查關聯表,大大的提高了資料庫性能,因為相對來說單表查詢比多表查詢要快。

xml和註解的關係

上面我們已經講了兩種方式的實現,下面來對比一下,兩種方式的關係:

必須有個一個XxxMapper.xml與之對應,方法名對應xml中的id,方法入參和方法出參都必須對應起來,很容易出問題。我們在開發的時候有的是可以使用代碼生成器生成,但是有的是必須自己手寫,有的公司也是要求必須手寫,所以這裡需要注意。

不需要

XxxMapper.xml

文件,只需要在對應

中的方法上加上註解就搞定了,但是這裡是有坑的。畢竟把sql放到了我們的Java代碼裡了。

優缺點

xml方式: 增加了xml文件,修改麻煩,條件不確定(ifelse判斷),容易出錯,特殊轉義字符比如大於小於 。

註解方式:複雜sql不好用,搜集sql不方便,管理不方便,修改需重新編譯

總結

本文講述了

的兩種映射方式,以及一些注意點,一些關係和區別。

實體屬性名和資料庫表欄位名不一樣的情況下,xml和註解分別是如何處理的。resultType和resultMap的區別。

相關焦點

  • MyBatis開發,你用 xml 還是註解?
    我之前認為 @Select 的方式是只能支持簡單 SQL 的書寫,對於一些類似於判空的需求是不支持的。(因為對 mybatis 註解開發確實不熟)比如在 xml 文件中這樣去寫:<when test='startPage !=nulland pageSize !
  • mybatis開發,你用 xml 還是註解?我 pick xml
    最近在看公司項目時發現有的項目mybatis是基於註解開發的,而我個人的習慣是基於xml文件開發。對於mybatis註解開發的原理理解不夠,於是翻閱了部分源碼,寫下此文。主要介紹了mybatis開發的兩種形式、三種寫法。還有一點瞎思考,介紹了一處騷代碼、還有一個坑。
  • 小學妹問:Mybatis常見註解有哪些?
    增刪改查註解總結其他註解@Results:結果映射的列表, 包含了一個特別結果列如何被映射到屬性或欄位的詳情。書 性:value, id。value 屬性是 Result 註解的數組。對應xml中的<resultMap> 標籤。
  • 最全MyBatis中XML映射文件標籤分析+示例
    注意:這裡參數如果直接只有一個的話可以不使用@Param註解,這樣在xml文件中可以直接使用JavaBean內的屬性名。如果使用了@Param註解,如下:int insert(@Param("userAddress") UserAddress userAddress);那麼xml文件中就可以使用#{userAddress.屬性名}來獲取屬性JavaBean內的屬性
  • Mybatis第三講 緩存與註解
    也就是要求實現Serializable接口,配置方法很簡單,只需要在映射XML文件配置就可以開啟緩存了 <cache/> ,如果我們配置了二級緩存就意味著:映射語句文件中的所有 select 語句將會被緩存。映射語句文件中的所欲 insert、update和delete 語句會刷新緩存。
  • 從零開始學SpringBoot之MyBatis-註解
    本節概述:(1) 關於mybatis(2) 註解思想(3) 新建項目並添加依賴項包(4) 創建啟動類App.java(5) 編寫實體類演示(6) 寫映射接口DemoMapper(7) 編寫服務類DemoService(8) 寫控制類DemoController(9) 配置資料庫連接池(10) 測試讓我們來看看這個部分:(1) 關於mybatis
  • Mybatis中mapper的xml解析詳解
    基礎介紹回顧下之前是在分析configuration的初始化過程,已經進行到了最後一步mapperElement(root.evalNode("mappers")),這個方法裡有兩種解析mapper的方法,一種是解析類,一種是解析xml文件,上一篇文章在講解析類中的註解,今天說到的就是解析xml
  • 最全MyBatis中XML映射文件(Mapper)標籤分析
    映射文件(keyProperty=&34;表示把主鍵的值設置到參數UserAddress類中的屬性id):<?/mapping/UserAddressMapper.xml&34;mybatis-config.xml&34;廣東深圳&34;插入成功數:&34;插入數據的主鍵為:&34;insert2&34;true&34;address&34;address&34;String&34;BEFORE&{address}) </insert>
  • Mybatis基本知識十九:註解式開發-動態Sql註解開發
    動態sql除了支持xml方式以外,還支持使用純註解的方式,與動態sql相關註解主要有四種:1.@SelectProvider 動態查詢SQL語句對應註解2.@InsertProvider 動態插入SQL語句對應註解3.
  • Mybatis中mapper相關註解解析類詳解
    基礎介紹根據MapperAnnotationBuilder和XMLMapperBuilder兩個的名字大概也可以猜出來他們的作用,MapperAnnotationBuilder應該是來處理mapper註解的,而XMLMapperBuilder是來處理mapper.xml文件的。
  • 詳解mybatis和Mybatis-Plus區別
    有一個前提,你得先在xml中寫好sql語句,是不是很麻煩?於是有下面的↓Mybatis Generator:自動為Mybatis生成簡單的增刪改查sql語句的工具,省去一大票時間,兩者配合使用,開發速度快到飛起。
  • MyBatis:複雜映射,配置深入
    ,將查詢結果自動封裝到實體類中resutlMap - 如果實體的屬性名與表中欄位名不一致,可以使用 resutlMap 實現手動封裝到實體類中編寫 UserMapper 接口List<User> findAllResultMap();
  • MyBatis:緩存,延遲加載,註解應用
    當用戶頻繁查詢某些固定的數據時,第一次將這些數據從資料庫中查詢出來,保存在緩存中。當用戶再次查詢這些數據時,不用再通過資料庫查詢,而是去緩存裡面查詢。減少網絡連接和資料庫查詢帶來的損耗,從而提高我們的查詢效率,減少高並發訪問帶來的系統性能問題。
  • 1.什麼是mybatis
    MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或註解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為資料庫中的記錄。
  • 別用註解了!教你用 Springboot 整合Mybatis
    我今天自己試著搭建了下Spring boot+Mybatis,發現比原來的Spring+SpringMVC+Mybatis簡單好多!!本文主要是講解下 Springboot 如何整合 MyBatis,這裡使用的是xml配置SQL而不是用註解。主要是 SQL和業務代碼應該隔離,方便和 DBA 校對 SQL。
  • 你知道目前最流行的Mybatis框架嗎?如何搭建呢?
    MyBatis可以使用簡單的XML或註解用於配置和原始映射,將接口和Java的POJO(Plain Old Java Objects,普通的Java對象)映射成資料庫中的記錄。Locattion:http://mybatis.org/dtd/mybatis-3-mapper.dtd (值與xml模板中對應) Key Type:URI Key:-//mybatis.org//DTD Mapper 3.0//EN (值與xml模板中對應) 第二步: 關閉xml,重新打開,如果重新打開不可以,重啟Eclipse即可。
  • Mybatis頻率最高的面試題及答案
    答:mybatis它是基於Java的持久層框架,內部封裝了JDBC的,是一個半自動化的框架,它可以通過簡單的xml或者註解的方式來配置和映射原生類型、Java的POJO以及接口。2,聽說過ORM嗎?答:ORM是對象映射的,為了解決關係型資料庫和簡單的Java對象(POJO)的映射關係,將程序中的對象自動持久化到關係型資料庫中。
  • SpringMVC+Mybatis 框架介紹
    一、Spring MVC框架要點1、為什麼選用SpringMVC(1)簡單易用,學習成本低,開發效率高(2)性能靈活,優於Struts(3)大眾框架,遇到問題網上有很多解決方案2、SpringMVC的註解類(1)@Controller註解定義控制器(2)@RequestMapping
  • 我們來繼續研究mybatis框架sql映射文件的屬性
    我們來繼續研究 mybatis 框架sql映射文件的屬性各位小夥伴開始我們今天的分享我們已經了解了 mybatis 框架的兩種使用方式以及主配置文件 (mybatis-config.xml) 的屬性。那麼今天我們來一起了解 sql 映射文件 (userMapper.xml) 的屬性。
  • mybatis-plus思維導圖,讓mybatis-plus不再難懂
    1mybatis-plus與mybatismybatisMybatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。