(1)-MyBatis基礎-----入門篇

MyBatis

MyBatis是java平臺下一款優秀的持久層框架,它支持定製化 SQL存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Ordinary Java Object,簡單普通的 Java對象)映射成數據庫中的記錄。

其前身爲apache的ibatis後來遷移到Gihub並更名爲MyBatis

MyBatis特點:

1.輕量級,自身不依賴其他任何JAR,但需要提供JDBC實現

​2.靈活,更加適用於需求變化頻繁的互聯網應用

​3.學習成本低,相比ORM框架而言,掌握MyBatis的使用是很輕鬆的

在結構中的位置

在這裏插入圖片描述
可以看出MyBatis處在DAO(數據訪問對象)的位置,處於模型層,用來處理數據庫操作的
回顧一下

DAO的工作職責

:

  • 連接數據庫

  • 接收輸入數據

  • ​拼接並執行SQL

  • ​解析並返回結果

爲什麼需要MyBatis

使用JDBC完成DAO層存在以下問題

  • 每次操作都需要手動的創建連接,最後關閉連接

    • 對於重複代碼通常開發者都會進行封裝,但是由於每個人的編碼風格不同導致封裝的代碼也沒有固定的套路

    • MyBatis將數據庫連接相關的參數放到配置XML中並封裝了創建連接的代碼

  • 頻繁的創建和銷燬連接

    • 由於數據庫連接使用的是TCP長連接,併發量大的系統中,這樣的方式會導致數據庫連接資源耗盡

    • MyBatis本身實現了連接池,可以解決這一問題,當然後續會更換其他更好的連接池

  • 接受參數拼接SQL語句並執行

    • 每一條SQL語句都是直接寫在代碼中(硬編碼),如果後期需求發生變化,則需要修改源碼中的SQL,然後重新編譯,測試…

    • MyBatis將SQL語句從代碼中剝離到Mapper.xml映射文件中

  • 解析結果

    • JDBC返回的是ResultSet,必須手動將其映射到一個個的對象中,同樣是重複度很高的代碼;並且存在硬編碼問題

    • MyBatis實現了入參映射到SQL參數,以及結果集映射到POJO對象

更多功能

MyBatis在解決上述問題的同時提供了更多實用的功能

  • 動態SQL,即在SQL語句中可以包含邏輯處理(判斷,循環等…)
  • 高級映射,支持一對一,一對多映射
  • 動態代理Mapper,使得可以用面向對象的方式來完成數據庫操作
  • 逆向工程,根據表結構自動生成,POJO,Mapper映射和Mapper接口,包含簡單的CRUD

MyBatis構架

在這裏插入圖片描述

  • SqlMapConfig.xml作爲全局配置,

    • 指定MyBatis的基本參數,如運行環境(開發,發佈),事務管理器,數據來源等;
    • 以及需要加載的mapper映射文件(從源碼中剝離出來的SQL語句)
  • SqlSessionFactory,負責讀取SqlMapConfig中的參數創建會話

  • SqlSession,通過SqlSessionFactory獲取一個Session(會話)

  • Executor 真正負責執行sql語句的對象

  • MappedStatement用於將輸入參數映射到sql語句,以及結果集映射到POJO

上述構架中,SqlSession以下的部分是MyBatis封裝好的,SqlSession負責調用它們完成操作; 開發過程中不需要涉及(特殊需求除外);

另外SqlSessionFactory和SqlSession也可以通過簡單的代碼獲取到,後續Spring框架能夠自動創建它們

所以使用MyBatis的重點就落在了SqlMapConfig.xml以及Mapper.xml中

CRUD入門

環境搭建

官方文檔:https://mybatis.org/mybatis-3/getting-started.html

1. 創建項目

這裏採用Maven來引入MyBatis,(詳見maven筆記之入土之路)項目採用普通的Java項目,不使用Maven骨架

2. 在pom.xml中添加依賴

<dependencies>
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version>
    </dependency>
    <dependency>
<groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version>
    </dependency>
    <dependency>
<groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version>
    </dependency>
    <dependency>
<groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version>
    </dependency>
</dependencies>

3.提供配置文件

3.1MyBatis全局配置

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
<!--        可配置多個環境  並指定默認使用的環境-->
        <environment id="development">
<!--            指定事務管理器-->
            <transactionManager type="JDBC"/>
<!--            指定數據源 就是數據來自哪裏 這裏默認使用MyBatis自帶的連接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--                //表示本機 localhost  &amp;就是&  xml中&需要轉譯-->
                <property name="url" value="jdbc:mysql:///mybatisDB?serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="admin"/>
            </dataSource>
        </environment>
    </environments>
<!--    指定要加載的映射文件-->
    <mappers>
        <mapper resource="mapper/ProductsMapper.xml"/>
    </mappers>
</configuration>

3.2 log4日誌模塊,定義輸出格式的配置
log4j.properties

#Global logging configuration
log4j.rootLogger=DEBUG, stdout  
#Console output... 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

這裏先書寫

第一個MyBatis案例根據id查詢

3.3 創建實體類以及對應表

CREATE DATABASE IF NOT EXISTS `mybatisDB` CHARACTER SET utf8;
USE `mybatisDB`;
DROP TABLE IF EXISTS `products`;
CREATE TABLE `products` (
 `pid` int(11) NOT NULL AUTO_INCREMENT,
 `pname` varchar(20) DEFAULT NULL,
 `price` double DEFAULT NULL,
 `pdate` date DEFAULT NULL,
 `cid` varchar(20) DEFAULT NULL,
 PRIMARY KEY (`pid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
INSERT INTO `products` VALUES (2,'新疆⼤棗',38,NULL,'s002'),(3,'新疆切
糕',68,NULL,'s001'),(4,'⼗三⾹',10,NULL,'s002'),(5,'⽼⼲爹',20,NULL,'s002'),(6,'泰
國咖喱',50.5,'2020-01-02','s001'),(7,'泰國咖喱2',50.5,'2020-01-02','s001');

得到數據庫表在這裏插入圖片描述
pojo實體類

package com.cx.pojo;

import java.util.Date;

/**
 *product實體類
 */
public class Product {
    private Integer pid;
    private String pname;
    private Double price;
    private Date pdate;
    private String cid;

    public Product() {
    }

    public Product(Integer pid, String pname, Double price, Date pdate, String cid) {
        this.pid = pid;
        this.pname = pname;
        this.price = price;
        this.pdate = pdate;
        this.cid = cid;
    }

    public Integer getPid() {
        return pid;
    }

    public void setPid(Integer pid) {
        this.pid = pid;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Date getPdate() {
        return pdate;
    }

    public void setPdate(Date pdate) {
        this.pdate = pdate;
    }

    public String getCid() {
        return cid;
    }

    public void setCid(String cid) {
        this.cid = cid;
    }

    @Override
    public String toString() {
        return "Product{" +
                "pid=" + pid +
                ", pname='" + pname + '\'' +
                ", price=" + price +
                ", pdate=" + pdate +
                ", cid='" + cid + '\'' +
                '}';
    }
}

3.4創建mapper.xml,直接操作數據庫,編寫sql語句
ProductsMapper.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">
<!--namespace 用於多個Mapper出現相同的sql時區分不同包-->
<mapper namespace="com.cx.pojo.Product">

		<!--查詢語句
    id用於表示這條sql
    
    parameterType 表示 sql語句接受一個整數參數
    
    resultType表示 將結果映射到Products對象中
    
    #{} 表示一個站位符等同於 ?
            若輸入參數是基礎數據類型則可以隨意寫
            若輸入是一個POJO則寫屬性名稱-->
    <select id="selectProductBtId" parameterType="int" resultType="com.yyh.pojo.Products">
        select *from products where pid = #{pid}
    </select>
  
</mapper>

注意: #{} 表示⼀個站位符等同於 ?,可以用來取值,若輸⼊參數是基礎數據類型則可以隨意寫,若輸⼊是⼀個POJO則寫屬性名稱,但是如何是在字符串中就不能用了,而要用KaTeX parse error: Expected 'EOF', got '#' at position 12: {} 如:pid = #̲{pid} ,pid li…{pid}%”

parameterType 輸入映射 表示 sql語句接受的參數類型,參數在sql語句中直接通過 #{} 或${} 取。

resultType 輸出映射,表示將結果映射到設定的類型中
不要忘記將這個mapper配置到mybatis-config.xml中

 <mappers>
        <mapper resource="mapper/ProductsMapper.xml"/>
 </mappers>

3.4書寫測試代碼

import com.cx.pojo.Product;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 *mybatis入門案例
 */
public class MyTest {
    @Test
    public void selectById() throws IOException 
     //1.加載核心配置文件mybatis-config.xml
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    //2.創建sqlsessionFactoryBuilder對象
    SqlSessionFactoryBuilder sqlsessionFactoryBuilder = new SqlSessionFactoryBuilder();
    //3.讀取配置文件的流,創建sqlSessionFactory會話 工廠
    SqlSessionFactory sqlSessionFactory = sqlsessionFactoryBuilder.build(inputStream);
    //4.創建Session對象
    SqlSession session = sqlSessionFactory.openSession();
    //5.執行查詢語句
    Product product = session.selectOne("selectById",3);

    System.out.println(product);
    session.close();
    }
}

點擊test輸出結果:
在這裏插入圖片描述
在這裏,出現了maven點擊test時出現亂碼:如圖
在這裏插入圖片描述
解決辦法見IDEA下使用Maven的test命令亂碼解決方案
那麼第一個案例就書寫完畢。selectOne只能是有兩個參數,一個是sql的id,一個是要傳遞的參數。
多個參數用map
總結一下步驟:

  1. 在pom.xml中引入相關jar包
  2. 創建全局配置文件,編寫數據庫參數
  3. 創建實體類,數據庫對應表
  4. 編寫對應mapper文件
  5. 加載核心配置文件mybatis-config.xml
  6. 創建SqlSessionFactoryBuilder對象,通過.build方法創建會話工廠,讀取流
  7. sqlSessionFactory.openSession創建sqlSession對象,執行sql語句。

案例2:模糊查詢

在ProductsMapper.xml增加標籤

<select id="selectProductLikeName" parameterType="string" resultType="com.yyh.pojo.Product">
  select *from products where pname like "%${pname}%"
</select>

測試代碼:由於多個測試方法都需要工廠所以講工廠作爲屬性並在,@Before中進行初始化,因爲每次都用的
此處不建議session也放在此處,因爲session不是線程安全的對象,所以不建議多個地方使用同一個。

private SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void before() throws IOException {
         //1.加載核心配置文件mybatis-config.xml
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    //2.創建sqlsessionFactoryBuilder對象
    SqlSessionFactoryBuilder sqlsessionFactoryBuilder = new SqlSessionFactoryBuilder();
    //3.讀取配置文件的流,創建sqlSessionFactory會話 工廠
    sqlSessionFactory = sqlsessionFactoryBuilder.build(inputStream);
    }

所以測試代碼:

 @Test
    public void selectProductLikeName(){
        //4.創建Session對象
    SqlSession session = sqlSessionFactory.openSession();
        //5.執行查詢語句
        List<Product> product = session.selectList("selectProductLikeName","新");
        System.out.println(product);
        session.close();
    }

輸出結果:
在這裏插入圖片描述
需要注意的是:在mapper中當需要做將參數進行字符串拼接時則不能在使用#{} 需更換爲${}表示將參數結果提取並拼接到字符串中

注意了:若MyBatis版本低於3.5.2 則在字符串中使用#{xxx}的方式將導致找不到屬性異常,在低版本中MyBatis將#{xxx}中的xxx當做參數的屬性去參數中查找get方法(很明顯找不到),在字符串內和字符串外獲取屬性的行爲竟然不同,好在3.5.2解決了這個問題

案例3:sql中需要多個參數用map

在ProductsMapper.xml增加標籤

<select id="selectByNameAndPrice" parameterType="map" resultType="com.cx.pojo.Product">
     select * from product where pname=#{pname} and price = #{price}
</select>

書寫測試代碼

@Test
    public void selectByNameAndPrice(){
         //4.創建Session對象
    SqlSession session = sqlSessionFactory.openSession();
        Map<String,Object> map = new HashMap<>();
        map.put("pname","⼗三⾹");
        map.put("price",10);
        //5.執行查詢語句
        Product product = session.selectOne("selectByNameAndPrice",map);
        System.out.println(product);
        session.close();
    }

運行結果
在這裏插入圖片描述

案例4:插入數據

在ProductsMapper.xml增加標籤

 <insert id="insertProduct" parameterType="com.cx.pojo.Product">
        insert into product values (null,#{pname},#{price},#{pdate},#{cid})
 </insert>

書寫測試代碼

@Test
    public void insertProduct(){
        //設置自動提交爲true  默認爲false
        //4.創建Session對象
    SqlSession session = sqlSessionFactory.openSession();
        Product product = new Product();
        product.setPrice(100d);
        product.setPname("糧食2789");
        product.setPdate(new Date());
        product.setCid("2222");
        //5.執行插入語
        int o = session.insert("insertProduct", product);
        session.commit();//手動提交
        System.out.println(o);
        session.close();
    }

運行結果:
在這裏插入圖片描述
強調:
當sql爲update insert delete時需要commit纔會生效,SqlSession默認不自動提交的,可以在獲取SqlSession時指定自動提交,也可以在執行完後手動調用commit;

sql爲update insert delete時返回值爲受影響行數

獲取插入數據的id

很多情況下需要獲取剛剛添加的記錄的id用來做表關聯,要獲得id有兩種方式

4.1對於支持自增的數據庫MySQL,下述案例:MyBatis會把id存儲到傳入對象的pid屬性中

 <insert id="insertProduct" parameterType="com.cx.pojo.Product" keyProperty="pid" useGeneratedKeys="true">
        insert into product values (null,#{pname},#{price},#{pdate},#{cid})
 </insert>

4.2兼容不支持自增的數據庫

 <insert id="insertProduct" parameterType="com.cx.pojo.Product">
        insert into product values (null,#{pname},#{price},#{pdate},#{cid})
        <!--指定如何獲取id 並放入對象某個屬性中 -->
        <selectKey resultType="int" keyProperty="pid" order="AFTER" >
            select last_insert_id();
        </selectKey>
 </insert>

注意:select last_insert_id();是mysql的函數,oracle沒有,那就需要將其替換爲oracle中生產id的函數,selectKey的原理是執行這個sql函數,然後將結果放入對象的屬性中,order指定id放入對象屬性是在執行sql前或者後

關於before和after的選擇,要根據id的來源是自增的還是自己編寫語句獲取的,如下:
在這裏插入圖片描述

案例5:更新數據

在ProductsMapper.xml增加標籤

<update id="updateProduct" parameterType="com.cx.pojo.Product">
        update product set
            pname=#{pname},
            price=#{price},
            pdate=#{pdate},
            cid=#{cid}
        where pid=#{pid}
    </update>

書寫測試代碼

@Test
    public void updateProduct(){
        //設置自動提交爲true 默認爲false
        //4.創建Session對象
    SqlSession session = sqlSessionFactory.openSession();
        Product product = session.selectOne("selectById", 3);
        product.setPrice(10d);
        product.setPname("哈密瓜");
        product.setPdate(new Date());
        product.setCid("s10022");
        //5.執行更新語
        int o = session.update("updateProduct", product);
        session.commit();//手動提交
        System.out.println(o);
        session.close();
    }

運行結果:
在這裏插入圖片描述

案例6:刪除案例

在ProductsMapper.xml增加標籤

<delete id="deleteById" parameterType="int">
        delete from product where pid = #{pid}
    </delete>

書寫測試代碼

 @Test
    public void deleteProduct(){
        //4.創建Session對象
    SqlSession session = sqlSessionFactory.openSession();
        //5.執行刪除語
        int o = session.delete("deleteById", 3);
        session.commit();//手動提交
        System.out.println(o);
        session.close();
    }

下一篇:MyBatis進階----進階篇

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章