首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MyBatis 實戰教程:從環境搭建到 Spring MVC 整合、分頁插件、動態 SQL 與代碼生成全棧指南

     編輯:Java 相關知識

前言:MyBatis 實戰全棧路徑

MyBatis 以「SQL 映射」聞名,靈活、透明、易調優。本教程從零開始,涵蓋環境搭建、接口式開發、CRUD 實戰、多表關聯查詢、Spring/Spring MVC 整合、物理分頁插件開發、動態 SQL 掌握、代碼生成器應用、Dao 層擴展九大模塊,構建生產級 MyBatis 應用知識體系。

一、開發環境搭建與首個查詢

1. 技術棧

  • IDE:Eclipse IDE for Java EE / IntelliJ IDEA
  • JDK 1.8+、MySQL 5.7+、MyBatis 3.5+
  • 依賴:mybatis-x.x.jar, mysql-connector-java.jar, log4j(日誌)

2. 核心配置文件 Configuration.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <typeAlias alias="User" type="com.example.model.User"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/example/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

3. 實體類與映射文件

// User.java
public class User {
    private int id; private String userName; private int userAge; private String userAddress;
    // getter/setter 省略
}

// UserMapper.xml
<?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.example.mapper.UserMapper">
    <select id="selectUserById" parameterType="int" resultType="User">
        select * from `user` where id = #{id}
    </select>
</mapper>

4. 測試啟動

Reader reader = Resources.getResourceAsReader("Configuration.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = sqlSessionFactory.openSession();
User user = session.selectOne("com.example.mapper.UserMapper.selectUserById", 1);
session.close();

二、接口式開發:告別字符串硬編碼

定義 Mapper 接口,方法名與映射文件 id 一致,參數與結果類型對應:

public interface UserMapper {
    User selectUserById(int id);
    List<User> selectUsers(String name);
    void insertUser(User user);
    void updateUser(User user);
    void deleteUser(int id);
}

映射文件 namespace 指向接口全限定名,調用方式:

UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1); // 類型安全、IDE 支援、重構友好

三、完整 CRUD 與事務控制

動態 SQL 片段複用

<sql id="Base_Column_List">
    id, user_name, user_age, user_address
</sql>
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
    insert into `user` (user_name, user_age, user_address)
    values (#{userName}, #{userAge}, #{userAddress})
</insert>
<update id="updateUser" parameterType="User">
    update `user` set user_name=#{userName}, user_age=#{userAge}, user_address=#{userAddress}
    where id=#{id}
</update>
<delete id="deleteUser" parameterType="int">
    delete from `user` where id=#{id}
</delete>

事務控制:增刪改必須 session.commit() 提交,異常時 session.rollback(),finally 中 session.close()。

四、多表關聯查詢:一對多、多對一實戰

場景:用戶 1:N 文章

// Article.java
public class Article {
    private int id; private User user; private String title; private String content;
    // getter/setter
}

方式一:<association> 多對一(文章 → 用戶)

<resultMap id="articleUserMap" type="Article">
    <id property="id" column="aid"/>
    <result property="title" column="title"/>
    <result property="content" column="content"/>
    <association property="user" javaType="User">
        <id property="id" column="id"/>
        <result property="userName" column="user_name"/>
        <result property="userAddress" column="user_address"/>
    </association>
</resultMap>
<select id="selectArticlesWithUser" resultMap="articleUserMap">
    select u.id, u.user_name, u.user_address, a.id aid, a.title, a.content
    from `user` u, `article` a where u.id = a.user_id
</select>

方式二:<collection> 一對多(用戶 → 文章列表)

<resultMap id="userArticlesMap" type="User">
    <id property="id" column="id"/>
    <result property="userName" column="user_name"/>
    <collection property="articles" ofType="Article">
        <id property="id" column="aid"/>
        <result property="title" column="title"/>
        <result property="content" column="content"/>
    </collection>
</resultMap>
<select id="selectUserWithArticles" parameterType="int" resultMap="userArticlesMap">
    select u.id, u.user_name, a.id aid, a.title, a.content
    from `user` u left join `article` a on u.id = a.user_id
    where u.id = #{id}
</select>

結果映射複用技巧

<resultMap id="userMap" type="User"> ... </resultMap>
<resultMap id="articleUserMap2" type="Article">
    ...
    <association property="user" resultMap="userMap"/> <!-- 直接引用已定義 resultMap -->
</resultMap>

五、Spring 整合:聲明式事務與 Mapper 掃描

核心 Bean 配置

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> ... </bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:config/Configuration.xml"/>
    <property name="mapperLocations" value="classpath*:com/example/mapper/*.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

Service 層注入 Mapper 接口,@Transactional 統一管理事務。

六、Spring MVC 整合:RESTful 服務構建

Controller 示例

@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired private UserMapper userMapper;
    @GetMapping("/{id}")
    public User getUser(@PathVariable int id) { return userMapper.selectUserById(id); }
    @GetMapping
    public List<User> listUsers(@RequestParam(defaultValue = "") String name) {
        return userMapper.selectUsers("%" + name + "%");
    }
    @PostMapping
    public void createUser(@RequestBody User user) { userMapper.insertUser(user); }
}

視圖解析器配置

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
</bean>

七、物理分頁插件開發:攔截器模式實戰

核心原理

實現 org.apache.ibatis.plugin.Interceptor,攔截 StatementHandler.prepare,重寫 SQL 追加分頁子句(MySQL LIMIT、Oracle ROWNUM),並自動執行 COUNT(*) 獲取總記錄數。

插件關鍵代碼片段

@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}))
public class PaginationInterceptor implements Interceptor {
    private String dialect = "mysql"; private String pageSqlIdPattern = ".*Page.*";
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
        BaseStatementHandler delegate = (BaseStatementHandler) ReflectUtil.getFieldValue(handler, "delegate");
        MappedStatement ms = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");
        if (ms.getId().matches(pageSqlIdPattern)) {
            BoundSql boundSql = delegate.getBoundSql();
            Object param = boundSql.getParameterObject();
            Page page = extractPage(param); // 從參數提取 Page 對象
            // 1. 執行 COUNT 查詢
            String countSql = "select count(0) from (" + boundSql.getSql() + ") tmp_count";
            // ... 設置參數、執行、設置 page.totalCount
            // 2. 改寫分頁 SQL
            String pageSql = buildPageSql(boundSql.getSql(), page, dialect);
            ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
        }
        return invocation.proceed();
    }
    // ... buildPageSql, extractPage 等輔助方法
}

配置啟用

<plugins>
    <plugin interceptor="com.example.plugin.PaginationInterceptor">
        <property name="dialect" value="mysql"/>
        <property name="pageSqlId" value=".*Page.*"/> <!-- 只有 id 匹配的語句才分頁 -->
    </plugin>
</plugins>

Controller 使用

@GetMapping("/page")
public PageResult<Article> pageArticles(@RequestParam int pageNum, @RequestParam int pageSize) {
    Page page = new Page((pageNum-1)*pageSize, pageSize);
    List<Article> list = articleMapper.selectArticlePage(page, userId); // Mapper 方法 id 含 "Page"
    return new PageResult<>(page.getTotalCount(), list);
}

八、動態 SQL 掌握:構建靈活查詢

標籤用途典型場景
<if>條件判斷參數非空時追加 WHERE 條件
<choose>/<when>/<otherwise>互斥分支多條件僅取一(如優先按 ID 查,否則按名稱)
<trim>前後綴處理動態構建 SET/WHERE 子句,自動去除多餘逗號/AND
<where>智能 WHERE自動補全 WHERE、去除首個 AND/OR
<set>智能 SETUPDATE 時自動補全 SET、去除尾部逗號
<foreach>集合遍歷IN 子句、批量 INSERT VALUES

<foreach> 批量插入範例

<insert id="batchInsert" parameterType="java.util.List">
    insert into student (name, sex, address, telephone, tid) values
    <foreach collection="list" item="item" separator=",">
        (#{item.name}, #{item.sex}, #{item.address}, #{item.telephone}, #{item.tId})
    </foreach>
</insert>

九、MyBatis Generator 代碼生成:告別重複勞動

配置文件 generatorConfig.xml 關鍵點

<context id="mysql" targetRuntime="MyBatis3">
    <commentGenerator>
        <property name="suppressAllComments" value="true"/> <!-- 簡潔代碼 -->
    </commentGenerator>
    <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://..." userId="root" password="pwd"/>
    <javaModelGenerator targetPackage="com.example.model" targetProject="src/main/java">
        <property name="enableSubPackages" value="true"/>
    </javaModelGenerator>
    <sqlMapGenerator targetPackage="com.example.mapper" targetProject="src/main/resources">
        <property name="enableSubPackages" value="true"/>
    </sqlMapGenerator>
    <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.mapper" targetProject="src/main/java">
        <property name="enableSubPackages" value="true"/>
    </javaClientGenerator>
    <table tableName="category" domainObjectName="Category">
        <property name="enableCountByExample" value="false"/> <!-- 禁用 Example 查詢 -->
    </table>
</context>

啟動生成

public class GeneratorMain {
    public static void main(String[] args) throws Exception {
        List<String> warnings = new ArrayList<>;
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(new File("src/main/resources/generatorConfig.xml"));
        DefaultShellCallback callback = new DefaultShellCallback(true);
        MyBatisGenerator generator = new MyBatisGenerator(config, callback, warnings);
        generator.generate(null);
    }
}

生成內容:Model、Mapper 接口、Mapper XML(含動態 WHERE Example)、Example 類(可選)。

十、Dao 層擴展:SqlSessionDaoSupport 整合 Spring

當 Mapper 接口無法滿足複雜邏輯(多表事務、存儲過程、動態數據源),自定義 Dao:

@Repository
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
    @Override
    public List<Article> getUserArticles(int userId) {
        return getSqlSession().selectList("com.example.mapper.UserMapper.selectUserArticles", userId);
    }
}

配置掃描 <context:component-scan base-package="com.example.dao"/>,Service 注入 UserDao 介面。

總結

MyBatis 實戰核心在於:接口式開發消除字符串硬編碼、動態 SQL 構建複雜查詢、結果映射解決關聯對象、分頁插件實現物理分頁、Generator 釋放重複勞動、Spring 整合統一事務管理。掌握這套體系,即可應對從簡單 CRUD 到複雜報表、高併發寫入的全谱系持久層需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved