【Mybatis】Mybatis快速入門

hudad發表於2024-06-17
  • MyBatis是一款優秀的 持久層 框架,用於簡化JDBC的開發。
  • MyBatis本是 Apache的一個開源專案iBatis,2010年這個專案由apache遷移到了google code,並且改名為MyBatis 。2013年11月遷移到Github。
  • 官網:https://mybatis.org/mybatis-3/zh/index.html

Mybatis入門

Mybatis會把資料庫執行的查詢結果,使用實體類封裝起來(一行記錄對應一個實體類物件)

Mybatis運算元據庫的步驟:

  1. 準備工作(建立springboot工程、資料庫表user、實體類User)
  2. 引入Mybatis的相關依賴,配置Mybatis(資料庫連線資訊)
  3. 編寫SQL語句(註解/XML)

匯入Mybatis依賴

<!-- 僅供參考:只貼上了pom.xml中部分內容 -->
<dependencies>
        <!-- mybatis起步依賴 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>

        <!-- mysql驅動包依賴 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- spring單元測試 (整合了junit) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

資料準備
建立使用者表user,並建立對應的實體類User。

建立user表
-- 使用者表
create table user(
    id int unsigned primary key auto_increment comment 'ID',
    name varchar(100) comment '姓名',
    age tinyint unsigned comment '年齡',
    gender tinyint unsigned comment '性別, 1:男, 2:女',
    phone varchar(11) comment '手機號'
) comment '使用者表';

-- 測試資料
insert into user(id, name, age, gender, phone) VALUES (null,'白眉鷹王',55,'1','18800000000');
insert into user(id, name, age, gender, phone) VALUES (null,'金毛獅王',45,'1','18800000001');
insert into user(id, name, age, gender, phone) VALUES (null,'青翼蝠王',38,'1','18800000002');
insert into user(id, name, age, gender, phone) VALUES (null,'紫衫龍王',42,'2','18800000003');
insert into user(id, name, age, gender, phone) VALUES (null,'光明左使',37,'1','18800000004');
insert into user(id, name, age, gender, phone) VALUES (null,'光明右使',48,'1','18800000005');
public class User {
    private Integer id;   //id(主鍵)
    private String name;  //姓名
    private Short age;    //年齡
    private Short gender; //性別
    private String phone; //手機號
    
    //省略GET, SET方法
}

配置Mybatis

application.properties:

#驅動類名稱
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#資料庫連線的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#連線資料庫的使用者名稱
spring.datasource.username=root
#連線資料庫的密碼
spring.datasource.password=1234

編寫SQL語句

在建立出來的springboot工程中,在引導類所在包下,在建立一個包 mapper。在mapper包下建立一個介面 UserMapper ,這是一個持久層介面(Mybatis的持久層介面規範一般都叫 XxxMapper)。

import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;

@Mapper
public interface UserMapper {
    
    //查詢所有使用者資料
    @Select("select id, name, age, gender, phone from user")
    public List<User> list();
    
}

@Mapper註解:表示是mybatis中的Mapper介面

  • 程式執行時:框架會自動生成介面的實現類物件(代理物件),並給交Spring的IOC容器管理

@Select註解:代表的就是select查詢,用於書寫select查詢語句

單元測試

在建立出來的SpringBoot工程中,在src下的test目錄下,測試類在執行時,會自動透過引導類載入Spring的環境(IOC容器)。我們要測試那個bean物件,就可以直接透過@Autowired註解直接將其注入進行,然後就可以測試了。
測試類程式碼如下:

@SpringBootTest
public class MybatisQuickstartApplicationTests {
	
    @Autowired
    private UserMapper userMapper;
	
    @Test
    public void testList(){
        List<User> userList = userMapper.list();
        for (User user : userList) {
            System.out.println(user);
        }
    }

}

執行結果:

User{id=1, name='白眉鷹王', age=55, gender=1, phone='18800000000'}
User{id=2, name='金毛獅王', age=45, gender=1, phone='18800000001'}
User{id=3, name='青翼蝠王', age=38, gender=1, phone='18800000002'}
User{id=4, name='紫衫龍王', age=42, gender=2, phone='18800000003'}
User{id=5, name='光明左使', age=37, gender=1, phone='18800000004'}
User{id=6, name='光明右使', age=48, gender=1, phone='18800000005'}

資料庫連線池

如果我們想把預設的資料庫連線池切換為Druid資料庫連線池,只需要完成以下兩步操作即可:

參考官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

1.在pom.xml檔案中引入依賴

<dependency>
    <!-- Druid連線池依賴 -->
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.8</version>
</dependency>

2.在application.properties中引入資料庫連線配置

spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.druid.username=root
spring.datasource.druid.password=1234

Mybatis基礎增刪改查

刪除

@Mapper
public interface EmpMapper {
    
    /**
     * 根據id刪除資料
     * @param id    使用者id
     */
    @Delete("delete from emp where id = #{id}")//使用#{key}方式獲取方法中的引數值
    public void delete(Integer id);
    
}

日誌輸入

#指定mybatis輸出日誌的位置, 輸出控制檯
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

新增

@Mapper
public interface EmpMapper {

    @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
    public void insert(Emp emp);

}

說明:#{...} 裡面寫的名稱是物件的屬性名

預設情況下,執行插入操作時,是不會主鍵值返回的。如果我們想要拿到主鍵值,需要在Mapper介面中的方法上新增一個Options註解,並在註解中指定屬性useGeneratedKeys=true和keyProperty="實體類屬性名"

@Mapper
public interface EmpMapper {
    
    //會自動將生成的主鍵值,賦值給emp物件的id屬性
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
    public void insert(Emp emp);

}

更新

@Mapper
public interface EmpMapper {
    /**
     * 根據id修改員工資訊
     * @param emp
     */
    @Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
    public void update(Emp emp);
    
}

查詢

根據ID查詢

@Mapper
public interface EmpMapper {
    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
    public Emp getById(Integer id);
}

注意

  • 實體類屬性名和資料庫表查詢返回的欄位名一致,mybatis會自動封裝。
  • 如果實體類屬性名和資料庫表查詢返回的欄位名不一致,不能自動封裝

解決方案:

  1. 起別名
  2. 結果對映
  3. 開啟駝峰命名

起別名:在SQL語句中,對不一樣的列名起別名,別名和實體類屬性名一樣

@Select("select id, username, password, name, gender, image, job, entrydate, " +
        "dept_id AS deptId, create_time AS createTime, update_time AS updateTime " +
        "from emp " +
        "where id=#{id}")
public Emp getById(Integer id);

手動結果對映:透過 @Results及@Result 進行手動結果對映

@Results({@Result(column = "dept_id", property = "deptId"),
          @Result(column = "create_time", property = "createTime"),
          @Result(column = "update_time", property = "updateTime")})
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);

開啟駝峰命名(推薦):如果欄位名與屬性名符合駝峰命名規則,mybatis會自動透過駝峰命名規則對映

# 在application.properties中新增:
mybatis.configuration.map-underscore-to-camel-case=true

要使用駝峰命名前提是 實體類的屬性 與 資料庫表中的欄位名嚴格遵守駝峰命名。

條件查詢

注意事項:
方法中的形參名和SQL語句中的引數佔位符名保持一致
使用MySQL提供的字串拼接函式:concat('%' , '關鍵字' , '%')

Mybatis動態SQL

Mybatis的XML配置檔案

Mybatis的開發有兩種方式:註解,XML

在Mybatis中使用XML對映檔案方式開發,需要符合一定的規範:

  1. XML對映檔案的名稱與Mapper介面名稱一致,並且將XML對映檔案和Mapper介面放置在相同包下(同包同名)
  2. XML對映檔案的namespace屬性為Mapper介面全限定名一致
  3. XML對映檔案中sql語句的id與Mapper介面中的方法名一致,並保持返回型別一致。

xml對映檔案中的dtd約束,直接從mybatis官網複製即可

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
 
</mapper>

配置:XML對映檔案的namespace屬性為Mapper介面全限定名

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">

</mapper>

配置:XML對映檔案中sql語句的id與Mapper介面中的方法名一致,並保持返回型別一致

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">

    <!--查詢操作-->
    <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        where name like concat('%',#{name},'%')
              and gender = #{gender}
              and entrydate between #{begin} and #{end}
        order by update_time desc
    </select>
</mapper>

動態SQL-if

<if>:用於判斷條件是否成立。使用test屬性進行條件判斷,如果條件為true,則拼接SQL。

<if test="條件表示式">
   要拼接的sql語句
</if>

示例:把SQL語句改造為動態SQL方式

  • 原有的SQL語句
<select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        where name like concat('%',#{name},'%')
              and gender = #{gender}
              and entrydate between #{begin} and #{end}
        order by update_time desc
</select>
  • 動態SQL語句
<select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        <where>
             <if test="name != null">
                 name like concat('%',#{name},'%')
             </if>
             <if test="gender != null">
                 and gender = #{gender}
             </if>
             <if test="begin != null and end != null">
                 and entrydate between #{begin} and #{end}
             </if>
        </where>
        order by update_time desc
</select>
  • <where>只會在子元素有內容的情況下才插入where子句,而且會自動去除子句的開頭的AND或OR
  • <set>:動態的在SQL語句中插入set關鍵字,並會刪掉額外的逗號。(用於update語句中)

動態SQL-foreach

SQL語句

delete from emp where id in (1,2,3);

Mapper介面:

@Mapper
public interface EmpMapper {
    //批次刪除
    public void deleteByIds(List<Integer> ids);
}

XML對映檔案:

  • 使用<foreach>遍歷deleteByIds方法中傳遞的引數ids集合
<foreach collection="集合名稱" item="集合遍歷出來的元素/項" separator="每一次遍歷使用的分隔符" 
         open="遍歷開始前拼接的片段" close="遍歷結束後拼接的片段">
</foreach>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
    <!--刪除操作-->
    <delete id="deleteByIds">
        delete from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>
</mapper> 

動態SQL-sql&include(使用範圍有限,不常用)

問題分析:

  • 在xml對映檔案中配置的SQL,有時可能會存在很多重複的片段,此時就會存在很多冗餘的程式碼

我們可以對重複的程式碼片段進行抽取,將其透過<sql>標籤封裝到一個SQL片段,然後再透過<include>標籤進行引用。

  • <sql>:定義可重用的SQL片段

  • <include>:透過屬性refid,指定包含的SQL片段

SQL片段: 抽取重複的程式碼

<sql id="commonSelect">
 	select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
</sql>

然後透過<include> 標籤在原來抽取的地方進行引用。操作如下:

<select id="list" resultType="com.itheima.pojo.Emp">
    <include refid="commonSelect"/>
    <where>
        <if test="name != null">
            name like concat('%',#{name},'%')
        </if>
        <if test="gender != null">
            and gender = #{gender}
        </if>
        <if test="begin != null and end != null">
            and entrydate between #{begin} and #{end}
        </if>
    </where>
    order by update_time desc
</select>

相關文章