Mybatis 中xml和註解映射,so easy啦

關注「Java後端技術全棧」 java

回覆「面試」獲取全套面試資料mysql

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

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

來自官網。sql

Mybatis映射九個頂級元素:數據庫

圖片

  • mapper:映射文件的根節點,只有一個屬性namespace(命名空間),做用以下:
  • 用於區分不一樣的mapper,全局惟一。
  • 綁定DAO接口,即面向接口編程,當綁定一個接口,就不用寫此接口的實現類,會經過接口的徹底限定名找到對應的mapper配置來執行SQL語句,因此,namespace的命名必需要寫接口的徹底限定名。
  • cache:配置給定命名空間的緩存。
  • cache-ref:從其餘命名空間引用緩存配置。
  • resultMap:用來描述數據庫結果集和對象的對應關係。
  • sql:能夠重用的SQL塊,也能夠被其餘語句引用。一般時存放一些公用性的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是同樣的。
  • 參數:整形,表示查詢語句傳入參數的類型和徹底限定名或別名。支持基礎數據類型和複雜數據類型。

{參數名}:告訴MyBatis生成的PreparedStatement參數,相對於JDBC中,改參數被標識爲‘?’。

別名與參數映射類型以下:緩存

返回類型中別名的使用,注意:數據結構

若是是咱們的entity類,那麼resultType是沒法使用別名的,只能使用resultMap纔可使用別名。mybatis

`<?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方法這裏就不貼了`
`}`

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">`
 `<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元素resultMap屬性的引用。
  • 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 settoString()方法這裏給省略, 但願你們在使用的使用,使用快捷鍵很簡單的就搞定了。

上面提到過resultTyperesultMap,那麼他們兩到底有什麼區別呢?

resultType和resultMap 有什麼區別?

  • resultType:直接表示返回類型, 包括基本數據類型和複雜數據類型。
  • resultMap:外部resultMap定義的引用,經過對應的外部resultMap的id,表示結果映射到哪一個resultMap上,通常用於字段名和屬性名不一致的狀況,或者須要作複雜的聯合查詢以便自由控制映射結果。
二者的關聯

當進行查詢時,查詢出來的每一個字段都會放在一個Map裏,當查詢元素返回屬性是resultType的時候,會將鍵值對取出賦所指定的屬性。其實MyBatis的每一個查詢映射的返回類型都是resultMap,只是當咱們使用resultType的時候,會自動把對應的值賦給所指定的對象屬性,當使用resultMap時候,由於map不是很好的表示領域,咱們就進一步的轉化爲對應的實體對象。resultMap主要做用於複雜的聯合查詢上。

resultMap的自動映射級別:默認級別爲PARTIAL,也能夠在settings更改值。

注意resultTyperesultMap本質是同樣的,都是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 class="com.tian.mybatis.mapper.UserMapper"/>`

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);`
`}`

輸出:

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

這樣也就是在使用註解的時候,處理實體屬性名和數據庫表字段名不同的問題的辦法。

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和註解的關係

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

xml方式

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

註解方式

不須要XxxMapper.xml文件,只須要在對應XxxMapper.java中的方法上加上註解就搞定了,可是這裏是有坑的。畢竟把sql放到了咱們的Java代碼裏了。

優缺點

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

註解方式:複雜sql很差用,蒐集sql不方便,管理不方便,修改需從新編譯

總結

本文講述了Mybatis的兩種映射方式,以及一些注意點,一些關係和區別。

實體屬性名和數據庫表字段名不同的狀況下,xml和註解分別是如何處理的。resultType和resultMap的區別。

推薦閱讀

6000多字 | 秒殺系統設計注意點【理論】

面試官:說說你對Java異常的理解

相關文章
相關標籤/搜索