mybatis基礎系列(二)——基礎語法、別名、輸入映射、輸出映射

来源:https://www.cnblogs.com/hjwublog/archive/2018/11/15/9965373.html
-Advertisement-
Play Games

增刪改查mapper根節點及其子節點mybatis框架需要讀取映射文件創建會話工廠,映射文件是以作為根節點,在根節點中支持9個元素,分別為insert、update、delete、select(增刪改查);cache、cache-ref、resultMap、parameterMap、sql。如下圖:... ...


增刪改查

mapper根節點及其子節點

mybatis框架需要讀取映射文件創建會話工廠,映射文件是以<mapper>作為根節點,在根節點中支持9個元素,分別為insert、update、delete、select(增刪改查);cache、cache-ref、resultMap、parameterMap、sql。如下圖:

image

命名空間

<mapper>根節點有個屬性namespace,作用是對sql語句進行分類化管理。

select節點

占位符#{}

一個<select>代表一條查詢語句,<select>常用屬性有id,parameterType,resultType。<select>節點的內容為sql語句,其語法與平常寫的sql語句相似,不同的地方是條件參數可以通過占位符#{}替換。例如:

sql語法:

SELECT * FROM t_emp WHERE empno=7369

mybitis中的語法:

SELECT * FROM t_emp WHERE empno=#{empno}

id:標誌映射文件中的sql,通常id也稱為statement的id。id的值就是xxxMapper.java中的方法名。

parameterType:執行sql語句中的輸入參數的類型。

resultType:指定sql輸出結果映射成java類型的對象。

#{}:表示一個占位符

#{id}:其中id表示接收輸入的參數,參數名稱就是id。#{}中的參數可以是任意對象。

示例與運行問題

EmpMapper.xml

<mapper namespace="com.itpsc.mapper.EmpMapper" >

<select id="queryById" parameterType="int" resultType="com.itpsc.entity.Emp">
  SELECT * FROM t_emp WHERE empno=#{empno}
</select>

</mapper>


//EmpMapper.java
public interface EmpMapper extends BaseMapper<Emp> {
    Emp queryById(Integer empno);
}

//EmpService.java
public interface EmpService {
    Emp queryById(Integer empno);
}

//EmpServiceImpl.java
@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper,Emp> implements EmpService {

    public EmpServiceImpl() {
        super();
    };
    public EmpServiceImpl(EmpMapper mapper) {
        this.baseMapper = mapper;
    };
    @Override
    public Emp queryById(Integer empno) {
        return this.baseMapper.queryById(empno);
    }
}

//EmpTests.java
@RunWith(SpringRunner.class)
@SpringBootTest
public class EmpTests {
    @Resource
    private EmpService empService;
    @Test
    public void contextLoads() {
    }
    @Test
    public void testQueryById() {
        System.out.println(empService.queryById(7369));
    }
}

運行報錯:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.itpsc.mapper.EmpMapper.queryById

找不到xml,發現在idea編譯後的classes路徑下並沒有相應的XML文件。

image

因為IDEA在編譯的時候忽略掉了XML文件,一個解決方法是將所有的XML文件移動到Resource文件夾下,這樣在編譯的時候就會將XML文件一起。

另一個方法是配置Maven不過濾src/main/java目錄下的.properties文件和.xml文件。

<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
    </resource>
</resources>

再次編譯就看到了classes目錄下有xml文件了。

image

運行test後輸出:

Emp{empno=7369, ename='SMITH', job='CLERK', mgr=7902, hiredate=Wed Dec 17 00:00:00 CST 1980, sal=800.0, comm=null, deptno=20}

拼接${}

${}:用來拼接sql字元串,將接收到的參數內容不加任何修飾拼接在sql語句中。

sql語法:

SELECT * FROM t_emp WHERE ename LIKE 'SMITH';

mybitis中的語法:

<select id="queryLikeName" parameterType="String" resultType="com.itpsc.entity.Emp">
  SELECT * FROM t_emp WHERE ename LIKE '${_parameter}'
</select>

註意

如果傳入的參數類型為String類型,則參數名需統一修改為_parameter,不能將參數設為bean里的名稱。

否則運行報錯為:There is no getter for property named 'preCode' in 'class java.lang.String


insert節點

一個<insert>代表一條insert語句,和<select>節點一樣,<insert>其語法與平常寫的sql語句相似,不同的地方是條件參數可以通過占位符#{}替換。

sql語法:

insert into t_emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(7100,’itpsc’,’developer’,7902,’1980-12-10’,1000.00,200.00,20)

mybitis中的語法:

<insert id="add" parameterType="com.itpsc.entity.Emp">
    insert into t_emp(empno,ename,job,mgr,hiredate,sal,comm,deptno)
    values(#{empno},#{ename},#{job},#{mgr},#{hiredate,jdbcType=DATE},#{sal},#{comm},#{deptno})
  </insert>

註意日期類型

mybatis日期類型的欄位,要加jdbcType=DATE。否則會報錯:There is no getter for property named 'hirdate' in 'class com.itpsc.entity.Emp'。

Mybatis中javaType和jdbcType對應關係

JDBC Type           Java Type  
CHAR                String  
VARCHAR             String  
LONGVARCHAR         String  
NUMERIC             java.math.BigDecimal  
DECIMAL             java.math.BigDecimal  
BIT             boolean  
BOOLEAN             boolean  
TINYINT             byte  
SMALLINT            short  
INTEGER             int  
BIGINT              long  
REAL                float  
FLOAT               double  
DOUBLE              double  
BINARY              byte[]  
VARBINARY           byte[]  
LONGVARBINARY               byte[]  
DATE                java.sql.Date  
TIME                java.sql.Time  
TIMESTAMP           java.sql.Timestamp  
CLOB                Clob  
BLOB                Blob  
ARRAY               Array  
DISTINCT            mapping of underlying type  
STRUCT              Struct  
REF                         Ref  
DATALINK            java.net.URL

insert與非自增主鍵返回

有時候新增記錄之後,需要這條新增記錄的主鍵,以便業務使用,但是新增之後再將其查詢出來明顯不合理,效率也變低了。mybatis可以將insert的記錄的主鍵返回。使用mysql的uuid()函數生成主鍵,需要修改表中id欄位類型為string,長度設置成35位。

mybatis的<selectKey>可以幫我們實現。Insert之前先通過uuid()查詢到主鍵,將主鍵輸入到sql語句中。

UserMapper.xml

<mapper namespace="com.itpsc.mapper.UserMapper" >
    <insert id="adduser" parameterType="com.itpsc.entity.User">
        <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
            SELECT uuid()
        </selectKey>
        insert into t_user(id,name,password,phone) values(#{id},#{name},#{password},#{phone})
    </insert>
</mapper>
測試
@Test
public void testAddUser() {
    User user = new User();
    //user.setId(1L);
    user.setName("uuid name1");
    user.setPassword("98764");
    user.setPhone("13877711111");
    System.out.println(userService.adduser(user));
    System.out.println(user.getId());
}

輸出:

1
9a64919e-b02f-11e8-8b1f-f48e38ec6bad

insert與自增主鍵返回

再將user表中的id欄位修改為Bigint類型,並設為自增。User.java中id修改為Long類型。通過mysql函數LAST_INSERT_ID()獲取到剛插入記錄的自增主鍵,是insert之後調用此函數。

<insert id="getIdAfterAdduser" parameterType="com.itpsc.entity.User">
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into t_user(name,password,phone) values(#{name},#{password},#{phone})
</insert>
@Test
public void getIdAfterAdduser() {
    User user = new User();
    user.setName("auto add id");
    user.setPassword("98764");
    user.setPhone("13877711111");
    System.out.println(userService.getIdAfterAdduser(user));
    System.out.println(user.getId());
}

運行輸出:
1
3

delete節點

sql語法:

delete FROM t_user WHERE id=3

mybitis中的語法:

delete FROM t_user WHERE id=#{id}

<delete id="delete" parameterType="java.lang.Long">
        DELETE from t_user WHERE id=#{id}
</delete>


update節點

<update id="updateById" parameterType="com.itpsc.entity.User">
        UPDATE t_user set NAME=#{name},password=#{password},phone=#{phone} WHERE id=#{id}
</update>

把整個java對象傳入,要更新哪些欄位sql語句決定。


占位符與拼接符小結

#{}表示一個占位符號,#{}接收輸入參數,類型可以是簡單類型也可以是複雜的數據類型。#{}接收對象值,通過OGNL語法(user.username)讀取對象中的屬性值。

${}表示一個拼接符號,會引用sql註入,不建議使用${}。${}接收輸入參數,類型可以是簡單類型也可以是複雜數據類型。${}接收對象值,通過OGNL語法(user.username)讀取對象中的屬性值。

出入參定義別名

批量定義別名

在mapper.xml中,定義很多的statement,statement需要parameterType指定輸入參數的類型、需要resultType指定輸出結果的映射類型。

如果在指定類型時輸入類型全路徑,不方便進行開發,可以針對parameterType或resultType指定的類型定義一些別名,在mapper.xml中通過別名定義,方便開發。

在springboot 的yml配置文件中通過type-aliases-package定義別名,在對parameterType或resultType指定的類型中就可以省略包名。

mybatis-plus:
   mapper-locations: "classpath:com/itpsc/mapper/**/*.xml"
   type-aliases-package: "com.itpsc.entity"
   global-config:
      db-column-underline: true

<insert id="adduser" parameterType="User">
    insert into t_user(name,password,phone) values(#{name},#{password},#{phone})
</insert>

輸入映射

parameterType


前面我們學習的輸入都是簡單對象,如果輸入參數的類型是複雜對象(包裝對象),該怎麼寫呢。

<select id="queryList" parameterType="com.itpsc.request.EmpRequest" resultType="com.itpsc.vo.EmpVo">
    SELECT * FROM t_emp WHERE deptno=#{emp.deptno} and job=#{emp.job}
  </select>
public interface EmpMapper extends BaseMapper<Emp> {
//...
    EmpVo queryList(EmpRequest request);
}

public class EmpRequest{
    private Emp emp;
    //其它條件
    public Emp getEmp() {
        return emp;
    }
    public void setEmp(Emp emp) {
        this.emp = emp;
    }
}


public class EmpVo extends Emp{
//...
}

使用parameterType進行輸入映射,類型是包裝對象,但是占位符里用的是被包裝對象的屬性。通過#{emp.deptno}取出被包裝對象的deptno屬性。


輸出映射

resultType

運行測試方法報錯:

org.mybatis.spring.MyBatisSystemException:
 nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

返回數據類型由xxxMapper.java介面中聲明的方法的返回類型和xxxMapper.xml文件共同決定。如果mapper方法返回單個對象(非集合對象),代理對象內部通過selectOne查詢資料庫。如果mapper方法返回集合對象,代理對象內部通過selectList查詢資料庫。不論是返回單一對象還是對象列表,xxxMapper.xml中的配置都是一樣的,都是resultMap=”***Map”或resultType=“* .* .*”類型。

例如:

返回單個對象resultType的值為"com.itpsc.entity.Emp"

返回多個對象resultType的值也是"com.itpsc.entity.Emp"

所以將mapper方法的返回類型聲明為List<Emp>即可。

使用resultType進行輸出映射,只有查詢出來的列名和對象中的屬性名一致,該列才可以映射成功。如果查詢出來的列名和對象中的屬性名全部不一致,沒有創建對象。只要查詢出來的列名和對象中的屬性有一個一致,就會創建對象。

如果我們把上面例子中的EmpVo 不繼承Emp,查詢出來就不創建對象。如下圖

image

image


resultMap

如果查詢出來的列名和對象的屬性名不一致,通過定義一個resultMap對列名和對象屬性名之間作一個映射關係。

1、定義resultMap

2、使用resultMap作為statement的輸出映射類型


<resultMap id="userMap" type="com.itpsc.entity.Emp" >
    <result column="_empno" property="empnum" jdbcType="INTEGER" />
    <result column="_ename" property="ename" jdbcType="VARCHAR" />
    <result column="_job" property="job" jdbcType="VARCHAR" />
    <result column="_mgr" property="mgr" jdbcType="INTEGER" />
    <result column="_hiredate" property="hiredate" jdbcType="DATE" />
    <result column="_sal" property="sal" jdbcType="REAL" />
    <result column="_comm" property="comm" jdbcType="REAL" />
    <result column="_deptno" property="deptno" jdbcType="INTEGER" />
  </resultMap>

  <select id="queryById" parameterType="int"resultMap ="userMap">
    SELECT empno _empno,ename _ename,job _job,mgr _mgr,hiredate _hiredate,sal _sal,comm _comm,deptno _deptno FROM t_emp WHERE empno=#{empno}
  </select>

本篇到此結束,下篇預告mybatis基礎系列(三)——動態sql。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • /etc 一、修改配置文檔(需要重啟網路配置,永遠生效) 1、修改IP地址[MariaDB@db1]$ vi /etc/sysconfig/network-scripts/ifcfg-eth0DEVICE=eth0ONBOOT=yesBOOTPROTO=staticIPADDR=192.168.30 ...
  • nginx不僅可以隱藏版本信息,還支持自定義web伺服器信息 先看看最終的隱藏結果吧 具體怎麼實現呢,其實也很簡單,請往下看 1 官網下載最新穩定版 2 解壓 3 修改C文件 (1)vim src/http/ngx_http_header_filter_module.c #修改49行 static ...
  • linux修改時間 伺服器時間與網路時間不符: 一、手動修改 1. date命令:查看當前時間 2. date -s 時分秒 :修改時間 還需要把日期改過來 3. date -s 完整日期時間(YYYY-MM-DD hh:mm[:ss]):修改日期、時間 時間要用雙引號括起來,否則報錯 手動修改會存 ...
  • 資料庫編碼 查看資料庫編碼 切換資料庫編碼 修改自增ID 創建表格時設置自增ID從N開始: 讓自增ID從預設值開始, 但是註意:這個命令會清空數據包記錄! 設置user表自增ID從123456開始 無法遠程登錄 在已經修改配置文件中的地址為 但仍然無法遠程登錄的情況下, 一般是需要對資料庫中的賬戶信 ...
  • redis主從複製 1.redis主從複製的作用 redis的定位是一個高可用的數據伺服器,可是在實際生產環境下,單機的redis伺服器是無法滿足真正意義上的高可用性的。 第一,單機的redis伺服器很容易發生單點故障,即使redis提供了各種持久化的方法來避免數據的丟失,但是物理上的故障(硬碟損毀 ...
  • 1、下載mysql的repo源 wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 2、安裝mysql-community-release-el7-5.noarch.rpm包 rpm -ivh mysql-commu ...
  • 1.為普通欄位添加索引,並且為索引命名 db.集合名.createIndex( {"欄位名": 1 },{"name":'idx_欄位名'}) 說明: (1)索引命名規範:idx_<構成索引的欄位名>。如果欄位名字過長,可採用欄位縮寫。 (2)欄位值後面的 1 代表升序;如是 -1 代表 降序。 2 ...
  • 接手的MongoDB只有一個日誌文件,體積非常大,排錯不便。在找解決辦法的時候發現MongoDB的啟動文件配置項超級多,於是產生瞭解釋配置參數的想法。 mongod服務有兩種啟動方式 一種是通過配置文件 $ ./mongod -f /app/mongodb/mongodb27017/conf/mon ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...