一、MyBatis 使用 XML 配置 SQL 總結


MyBatis 是一款優秀的基於 Java 的持久層框架,它內部封裝了 JDBC 操作數據庫的繁瑣細節,使開發者只需要關注 SQL 語句本身,后期再結合 Spring 框架的依賴注入,大大減少了操作數據庫的代碼量,從而提高開發效率。

MyBatis 可以通過 XML 方式配置 SQL 語句,也可以通過注解的方式編寫 SQL 語句,具體采用哪種方式取決於公司的開發規定,建議兩種開發方式都要掌握,其實兩種方式都很容易。

MyBatis 的官網地址為:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

本篇博客主要介紹 MyBatis 使用 XML 配置 SQL 語句的方式實現對數據庫操作的具體細節,在博客的最后面會提供源代碼。


一、導入 jar 包

新建一個 Maven 項目,在 pom.xml 文件中導入 4 個 jar 包:

mysql 的 jar 包:https://mvnrepository.com/artifact/mysql/mysql-connector-java

mybatis 的 jar 包:https://mvnrepository.com/artifact/org.mybatis/mybatis

log4j 的 jar 包:https://mvnrepository.com/artifact/log4j/log4j

junit 的 jar 包:https://mvnrepository.com/artifact/junit/junit

我在 pom.xml 配置的都是當前最新版本的 jar 包,如下所示:

<!--導入 mysql 的 jar 包-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

<!--導入 mybatis 的 jar 包-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.9</version>
</dependency>

<!--導入 log4j 的 jar 包-->
<!--主要是為了查看 mybatis 生成的最終 sql 語句-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

<!--導入 junit 的 jar 包-->
<!--方便編寫測試方法,對 mybatis 操作數據庫進行測試-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

配置好引用的 jar 包后,打開右側的 Maven 窗口,刷新一下,這樣 Maven 會自動下載所需的 jar 包文件。


二、搭建整個項目工程

整個項目工程的結構和整體內容,如下圖所示,

image

項目工程結構簡單介紹:

com.jobs.bean 包下存放的是實體類
com.jobs.mapper 包下存放的是 Mybatis 操作數據庫的接口
com.jobs.service 包下存放的是使用 Mybatis 的類庫操作數據的業務方法

resources 目錄下的配置文件介紹:
com.jobs.mapperXML 下的 employeeMapper.xml 是對應 com.jobs.mapper 包下接口的 sql 語句配置文件
jdbc.properties 是數據庫連接參數的文件
log4j.properties 是配置 log4j 日志輸出參數的文件
MyBatisConfig.xml 是 MyBatis 的核心配置文件

test 目錄下的文件介紹:
com.jobs.employeeTest 類是專門用來編寫 junit 單元測試方法的,用來測試 MyBatis 是否搭建成功


三、編寫配置文件內容

jdbc.properties 文件配置數據庫連接信息,內容如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testdb
username=root
password=123456

log4j.properties 文件配置控制台日志輸出的信息,內容如下:

# 輸出 debug 以上的所有類型的日志信息(DEBUG INFO WARN ERROR FATAL)
# stdout 配置項的名稱(表明使用下面的 log4j.appender.stdout 對應的配置)
log4j.rootLogger=DEBUG, stdout
# log4j.appender.stdout 配置的是控制台輸出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 該項配置表示要自定義日志顯示的格式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 自定義日志顯示格式:
# %p 表示輸出每條日志的級別信息(DEBUG INFO WARN ERROR FATAL)
# %t 表示輸出產生日志的線程的名稱
# %m 表示輸出具體的日志信息
# %n 表示根據當前操作系統類型,輸出一個回車換行
log4j.appender.stdout.layout.ConversionPattern=%p [%t] - %m%n

MyBatisConfig.xml 文件是 MyBatis 的核心配置文件,配置內容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!--引入MyBatis 的 DTD 約束-->
<!DOCTYPE configuration PUBLIC
        "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <!--引入數據庫連接的配置文件-->
    <properties resource="jdbc.properties"/>

    <!--引入 log4j 日志,方便查看運行過程中所生成的 sql 語句-->
    <settings>
        <setting name="logImpl" value="log4j"/>
    </settings>

    <!--為實體類 bean 起別名,這樣就可以在 SQL 配置文件中直接使用 bean 的類名代替全限定類名-->
    <typeAliases>
        <!--如果實體類 bean 比較少的話,可以采用 typeAlias 逐個配置-->
        <!--<typeAlias type="com.jobs.bean.employee" alias="employee"/>-->
        <!--絕大多數情況下,都是直接配置實體類 bean 所在的包,這樣包下所有的實體類都自動配置-->
        <package name="com.jobs.bean"/>
    </typeAliases>

    <!--environments 配置數據庫環境,環境可以有多個。default 屬性指定使用的是哪個-->
    <environments default="mysql">
        <!--environment配置數據庫環境,id屬性唯一標識-->
        <environment id="mysql">
            <!--transactionManager 事務管理,這里采用 JDBC 默認的事務-->
            <transactionManager type="JDBC"></transactionManager>
            <!--dataSource 數據源信息,這里采用連接池-->
            <dataSource type="POOLED">
                <!--通過引入的 jdbc.properties 文件中的 key 獲取數據庫連接的配置信息-->
                <property name="driver" value="${driver}" />
                <property name="url" value="${url}" />
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- mappers 引入操作數據庫的接口映射配置文件 -->
    <mappers>
        <!-- 如果有多個接口映射配置文件,可以添加多個 mapper 配置-->
        <mapper resource="com/jobs/mapperXML/employeeMapper.xml"/>
    </mappers>
</configuration>

四、數據庫表和實體類

MySQL 數據庫下創建了 testdb 數據庫,里面創建了一張 employee 表,具體 SQL 語句如下:

-- 創建數據庫
CREATE DATABASE IF NOT EXISTS `testdb`;

USE `testdb`;

-- 創建表
CREATE TABLE IF NOT EXISTS `employee` (
  `e_id` int(11) NOT NULL AUTO_INCREMENT,
  `e_name` varchar(50) DEFAULT NULL,
  `e_age` int(11) DEFAULT NULL,
  PRIMARY KEY (`e_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- 向表中添加數據
INSERT INTO `employee` (`e_id`, `e_name`, `e_age`)
VALUES(1, '侯胖胖', 25),(2, '楊磅磅', 23),
(3, '李噸噸', 33),(4, '任肥肥', 35),(5, '喬豆豆', 32);

com.jobs.bean.employee 實體類的內容如下:(這里故意讓【實體類的字段】與【數據庫的字段】名稱不一樣

package com.jobs.bean;

public class employee {
    //主鍵id
    private Integer id;
    //姓名
    private String name;
    //年齡
    private Integer age;

    public employee() {
    }

    public employee(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    //方便將員工信息在控制台打印出來查看
    @Override
    public String toString() {
        return "employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

五、Mapper 接口和 SQL 配置

這里采用 Mybatis 的動態代理開發方式實現持久層的開發,這種方式是市場上各個企業普遍采用的方式。

Mapper 接口:操作數據庫的接口文件
Mapper.xml:該文件為 Mapper 接口 中的每個方法,配置連接數據庫后具體要執行的 SQL 語句

Mapper 接口 和 Mapper.xml 必須遵守以下開發規范:

  • Mapper.xml 文件中的 namespace 與 Mapper接口 的全限定名相同

  • Mapper 接口方法名和 Mapper.xml 中定義的每個 statement 的 id 相同

  • Mapper 接口方法的輸入參數類型和 Mapper.xml 中定義的每個 sql 的 parameterType 的類型相同

  • Mapper 接口方法的輸出參數類型和 mapper.xml 中定義的每個 sql 的 resultType 的類型相同

  • 如果 sql 語句返回的字段名稱與實體類的字段名稱不一致,可以通過 resultMap 提前兩者之間的字段對應關系


下面列出 com.jobs.mapper.employeeMapper 這個 Mapper 接口 的內容:
package com.jobs.mapper;

import com.jobs.bean.employee;
import java.util.List;

public interface employeeMapper {

    //查詢全部
    List<employee> selectAll();

    //根據id查詢
    employee selectById(Integer id);

    //新增數據
    Integer insert(employee ele);

    //修改數據
    Integer update(employee ele);

    //刪除數據
    Integer delete(Integer id);

    //根據條件查詢
    List<employee> selectCondition(employee ele);

    //根據多個id查詢
    List<employee> selectByIds(List<Integer> ids);
}

然后列出 resources 目錄下 com/jobs/mapperXML/employeeMapper.xml 這個 Mapper.xml 文件的內容:

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD約束-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace 名稱空間,必須配置為 Mapper 接口的全限定名-->
<mapper namespace="com.jobs.mapper.employeeMapper">
    <!--由於【數據庫字段】與【bean實體類字段】不一致,
	因此這里需要配置【數據庫字段】和【bean實體類字段】的對應關系-->
    <resultMap id="employee_map" type="employee">
        <id column="e_id" property="id" />
        <result column="e_name" property="name" />
        <result column="e_age" property="age" />
    </resultMap>

    <!--配置公用的 SQL 語句,方面下面進行引用-->
    <sql id="select" >SELECT e_id,e_name,e_age FROM employee</sql>

    <!--查詢全部,這里的 id 必須與  Mapper 接口中的對應的方法名稱完全相同-->
    <!--resultMap 表示將查詢結構中每條記錄,封裝成 employee_map 所對應的 employee 實體對象-->
    <select id="selectAll" resultMap="employee_map">
        <!--引用上面配置的公用 SQL 語句-->
        <include refid="select"/> order by e_id;
    </select>

    <!--根據id查詢,parameterType 表示傳入的參數類型-->
    <select id="selectById" resultMap="employee_map" parameterType="int">
        <include refid="select"/> WHERE e_id = #{id}
    </select>

    <!--新增數據,由於在 Mybatis 的核心配置文件,已經配置了 bean 的別名即為類名
	因此這里可以直接使用 bean 的類名作為參數類型-->
    <insert id="insert" parameterType="employee">
        insert into employee(e_id,e_name,e_age) VALUES (#{id},#{name},#{age})
    </insert>

    <!--修改數據-->
    <update id="update" parameterType="employee">
        UPDATE employee SET e_name = #{name},e_age = #{age} WHERE e_id = #{id}
    </update>

    <!--刪除數據-->
    <delete id="delete" parameterType="int">
        DELETE FROM employee WHERE e_id = #{id}
    </delete>

    <!--根據條件查詢-->
    <select id="selectCondition" resultMap="employee_map" parameterType="employee">
        <include refid="select"/>
        <where>
            <!--根據條件,動態拼接SQL語句-->
            <if test="id != null">
                e_id = #{id}
            </if>
            <if test="name != null">
                AND e_name like CONCAT('%',#{name},'%')
            </if>
            <if test="age != null">
                AND e_age = #{age}
            </if>
        </where>
        order by e_id desc
    </select>

    <!--根據多個id查詢-->
    <select id="selectByIds" resultMap="employee_map" parameterType="list">
        <include refid="select"/>
        <where>
            <!--通過循環拼接 SQL 語句-->
            <foreach collection="list" open="e_id IN (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
</mapper>

六、編寫 Service 方法訪問數據庫

Service 里面的方法定義可以與 Mapper 接口中的方法不一樣,這里為了方便,就保持一致了。
com.jobs.service.employeeService 的內容如下所示:

package com.jobs.service;

import com.jobs.bean.employee;
import com.jobs.mapper.employeeMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class employeeService {

    //查詢所有
    public List<employee> selectAll() {
        List<employee> list = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            //加載核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //獲取SqlSession工廠對象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通過工廠對象獲取SqlSession對象,openSession 的參數為 true 表示自動提交事務
            //對於增刪改操作,如果 openSession 為 false,
            //在程序代碼最后需要通過 sqlSession.commit() 提交事務,才能使寫操作生效
            sqlSession = sqlSessionFactory.openSession(true);
            //通過動態代理獲取StudentMapper接口的實現類對象
            employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
            //調用接口方法
            list = mapper.selectAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }

    //根據id查詢單個員工
    public employee selectById(Integer id) {
        employee ele = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
            ele = mapper.selectById(id);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ele;
    }

    //新增
    public Integer insert(employee ele) {
        Integer result = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
            result = mapper.insert(ele);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    //修改
    public Integer update(employee ele) {
        Integer result = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
            result = mapper.update(ele);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //6.釋放資源
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    //刪除
    public Integer delete(Integer id) {
        Integer result = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
            result = mapper.delete(id);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    //根據條件查詢
    public List<employee> selectCondition(employee ele) {
        List<employee> list = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
            list = mapper.selectCondition(ele);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }

    //根據多個id查詢
    public List<employee> selectByIds(List<Integer> ids) {
        List<employee> list = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
            list = mapper.selectByIds(ids);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }
}

上面有很多重復代碼,有興趣的話,可以自己進行一下封裝。實際上也沒有封裝的必要,因為后面使用 Spring 框架集成了 MyBatis 后,上面的很多代碼根本就不需要寫了。


七、使用 junit 測試驗證

com.jobs.employeeTest 類編寫的測試方法內容如下所示:

package com.jobs;

import com.jobs.bean.employee;
import com.jobs.service.employeeService;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;

public class employeeTest {

    private employeeService service = new employeeService();

    //查詢全部測試
    @Test
    public void selectAll() {
        List<employee> elist = service.selectAll();
        for (employee ele : elist) {
            System.out.println(ele);
        }
    }

    //根據id查詢測試
    @Test
    public void selectById() {
        employee ele = service.selectById(3);
        System.out.println(ele);
    }

    //新增測試
    @Test
    public void insert() {
        employee ele = new employee(6, "任天蓬", 26);
        Integer result = service.insert(ele);
        System.out.println(result);
    }

    //修改測試
    @Test
    public void update() {
        employee ele = new employee(6, "任天蓬", 16);
        Integer result = service.update(ele);
        System.out.println(result);
    }

    //根據條件動態生成SQL語句查詢測試
    @Test
    public void selectCondition() {
        //可以同時啟用多個條件,根據條件動態拼接 SQL 語句
        employee ele = new employee();
        //ele.setId(4); //通過 id 查詢
        ele.setName("任"); //通過姓名模糊查詢
        //ele.setAge(35); //通過年齡查詢
        List<employee> elelist = service.selectCondition(ele);
        for (employee empl : elelist) {
            System.out.println(empl);
        }
    }

    //根據多個 id 查詢測試
    @Test
    public void selectByIds() {
        ArrayList<Integer> ids = new ArrayList<>(List.of(1,2,3));
        List<employee> elelist = service.selectByIds(ids);
        for (employee empl : elelist) {
            System.out.println(empl);
        }
    }

    //刪除測試
    @Test
    public void delete() {
        Integer result = service.delete(6);
        System.out.println(result);
    }
}

OK,到此為止,已經快速介紹完畢,希望對大家有用,源代碼下載地址如下:
https://files.cnblogs.com/files/blogs/699532/MybatisXmlCode.zip




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM