最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

從入門到精通詳解SpringBoot整合MyBatis的全攻略

 更新時間:2026年05月28日 09:29:03   作者:xiaoyu?  
在 Java 持久層框架的版圖中,MyBatis 無疑占據著舉足輕重的地位,本文詳細解析了MyBatis核心架構,SpringBoot整合方式,動態(tài)SQL與緩存機制并分頁的方案,希望對大家有一定的幫助

一、初識 MyBatis:為什么它如此受歡迎?

在 Java 持久層框架的版圖中,MyBatis 無疑占據著舉足輕重的地位。它是一個優(yōu)秀的半自動 ORM(對象關系映射)框架,能夠將 Java 對象與數據庫記錄進行映射,支持自定義 SQL、存儲過程以及高級映射。相比于 Hibernate 的全自動 ORM,MyBatis 允許開發(fā)者直接編寫 SQL,在需要精細控制 SQL 執(zhí)行和復雜查詢的場景中,展現出無可比擬的靈活性和性能優(yōu)勢。

簡單來說,MyBatis 的核心工作就是 將 SQL 語句與 Java 代碼解耦,通過 XML 或注解的配置方式,讓你既能享受框架帶來的便捷,又能牢牢掌控 SQL 的每一個細節(jié)。正因如此,MyBatis 在國內的 Java 開發(fā)社區(qū)中堪稱“半壁江山”,幾乎是企業(yè)級項目數據訪問層的標準配置。

1.1 MyBatis 的核心優(yōu)勢

SQL 與代碼解耦:MyBatis 通過 XML 或注解方式將 SQL 語句與 Java 代碼分離,開發(fā)者可獨立維護數據庫操作邏輯。DBA 可以直接優(yōu)化 SQL 而無需修改業(yè)務代碼,這在需要精細控制 SQL 的遺留系統(tǒng)遷移場景中尤為珍貴。

動態(tài) SQL 靈活構建:MyBatis 提供 <if><choose>、<foreach> 等標簽實現條件拼接,相比于 JPA 的 Criteria API,MyBatis 的動態(tài) SQL 更接近原生 SQL 語法,調試成本可降低 60% 以上。

性能優(yōu)化空間巨大:一級緩存默認開啟,可減少重復查詢,緩存命中率可達 35%;延遲加載通過 fetchType="lazy" 實現關聯對象按需加載,避免 N+1 查詢問題;批處理模式下,1000 條插入操作可從 10 秒壓縮至 2 秒。

數據庫兼容性強:支持 Oracle、MySQL、PostgreSQL 等 12 種主流數據庫,通過 typeAliastypeHandlers 可無縫適配特殊數據類型。

1.2 MyBatis 的局限性

當然,任何框架都不是萬能的。當實體類包含 50+ 字段時,XML 映射文件容易變得臃腫(單個實體映射文件超過 800 行時,字段修改導致的維護錯誤率可能上升 40%)。此外,分頁需要手動處理,相比 MyBatis-Plus 的自動分頁略顯繁瑣。

二、MyBatis 核心架構解析

2.1 核心組件

MyBatis 的核心組件如同一個精密的機器,各司其職:

組件作用
SqlSessionFactoryBuilder使用建造者模式,解析配置文件并創(chuàng)建 SqlSessionFactory
SqlSessionFactory工廠類,用于創(chuàng)建 SqlSession,應設計為單例
SqlSession代表一次數據庫會話,提供增刪改查 API,線程不安全
Configuration存儲全局配置信息、映射信息、類型處理器,是 MyBatis 的“大腦”
Executor執(zhí)行器,負責執(zhí)行 SQL,維護一級緩存
StatementHandler封裝 JDBC Statement 的操作
ParameterHandler負責處理 SQL 參數
ResultSetHandler負責結果集的映射

2.2 一條 SQL 的執(zhí)行全流程

以執(zhí)行一次 userMapper.selectUserById(1) 為例,背后的故事是這樣的:

1. 初始化
   ├─ SqlSessionFactoryBuilder → 構建 SqlSessionFactory
   └─ SqlSessionFactory → 解析 XML/注解,構建 Configuration

2. 獲取 SqlSession
   └─ SqlSessionFactory.openSession() → 創(chuàng)建 DefaultSqlSession

3. Mapper 動態(tài)代理
   └─ UserMapper mapper = sqlSession.getMapper(UserMapper.class)(生成 MapperProxy 代理對象)

4. 執(zhí)行 SQL
   ├─ mapper.selectUserById(1)
   ├─ MapperProxy.invoke() → 根據方法找到 MappedStatement
   └─ SqlSession.selectOne(mappedStatement, params)

5. Executor 執(zhí)行
   ├─ CachingExecutor (二級緩存) → delegate → SimpleExecutor
   ├─ 創(chuàng)建 StatementHandler
   ├─ ParameterHandler 設置參數
   ├─ JDBC PreparedStatement 執(zhí)行 SQL
   └─ ResultSetHandler 映射結果

6. 返回結果

整個流程的核心在于:配置 → SqlSessionFactory → SqlSession → Executor → MappedStatement → 數據庫。

2.3 MappedStatement 的秘密

MappedStatement 是 MyBatis 中一個關鍵的底層封裝對象,它包裝了 MyBatis 配置信息及 SQL 映射信息。mapper.xml 文件中的一個 SQL 對應一個 MappedStatement 對象,SQL 的 id 就是 MappedStatement 的 id。在 SQL 執(zhí)行前,Executor 通過 MappedStatement 將輸入的 Java 對象映射至 SQL 中;執(zhí)行后,再將輸出結果映射至 Java 對象中。

三、Spring Boot 整合 MyBatis(實戰(zhàn)篇)

3.1 依賴導入

在 Spring Boot 項目中整合 MyBatis,首先需要在 pom.xml 中添加相關依賴:

<!-- MyBatis Spring Boot Starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.3.2</version>
</dependency>
<!-- MySQL 驅動 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- 可選:連接池(HikariCP 已默認包含) -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>

小貼士mybatis-spring-boot-starter 會自動引入 mybatismybatis-spring 依賴,我們只需添加這一個 starter 即可。

3.2 配置文件詳解(application.yml)

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 10              # 最大連接池數
      minimum-idle: 5                     # 最小空閑連接
      connection-timeout: 30000           # 連接超時時間
      idle-timeout: 600000                # 空閑超時時間
      max-lifetime: 1800000               # 連接最大生命周期
mybatis:
  # 實體類包路徑,用于別名自動注冊
  type-aliases-package: com.example.demo.entity
  # Mapper XML 文件位置
  mapper-locations: classpath:mapper/*.xml
  configuration:
    # 開啟駝峰命名自動映射(例如:user_name → userName)
    map-underscore-to-camel-case: true
    # 開啟二級緩存
    cache-enabled: true
    # 開啟延遲加載
    lazy-loading-enabled: true
    # 日志輸出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

關鍵配置解讀:

  • map-underscore-to-camel-case: true:這個配置非常實用!開啟后,數據庫字段 user_name 會自動映射到 Java 實體類的 userName 屬性,省去了大量手動映射的煩惱。
  • type-aliases-package:指定實體類包路徑后,在 Mapper XML 中就可以直接使用類名(小寫形式)而非全限定名。
  • mapper-locations:指定 XML 映射文件的存放位置。

3.3 基于 XML 的開發(fā)方式

這是 MyBatis 最經典的開發(fā)模式,適合復雜的 SQL 映射場景。

Step 1:創(chuàng)建實體類

package com.example.demo.entity;

import lombok.Data;
import java.util.Date;

@Data
public class User {
    private Long id;
    private String userName;
    private String password;
    private String email;
    private Integer age;
    private Integer status;
    private Date createTime;
    private Date updateTime;
}

Step 2:創(chuàng)建 Mapper 接口

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;

@Mapper
public interface UserMapper {
    User selectUserById(@Param("id") Long id);
    List<User> selectUserList(@Param("userName") String userName);
    int insertUser(User user);
    int updateUser(User user);
    int deleteUserById(@Param("id") Long id);
}

Step 3:編寫 Mapper XML 文件

src/main/resources/mapper/ 目錄下創(chuàng)建 UserMapper.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">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <!-- 結果映射 -->
    <resultMap id="BaseResultMap" type="User">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <result column="user_name" property="userName" jdbcType="VARCHAR"/>
        <result column="password" property="password" jdbcType="VARCHAR"/>
        <result column="email" property="email" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
        <result column="status" property="status" jdbcType="INTEGER"/>
        <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
        <result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
    </resultMap>
    <!-- 基礎字段列表 -->
    <sql id="Base_Column_List">
        id, user_name, password, email, age, status, create_time, update_time
    </sql>
    <!-- 根據 ID 查詢用戶 -->
    <select id="selectUserById" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List"/>
        FROM user
        WHERE id = #{id}
    </select>
    <!-- 條件查詢用戶列表 -->
    <select id="selectUserList" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List"/>
        FROM user
        WHERE 1=1
        <if test="userName != null and userName != ''">
            AND user_name LIKE CONCAT('%', #{userName}, '%')
        </if>
        ORDER BY create_time DESC
    </select>
    <!-- 插入用戶 -->
    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user (user_name, password, email, age, status, create_time, update_time)
        VALUES (#{userName}, #{password}, #{email}, #{age}, #{status}, NOW(), NOW())
    </insert>
    <!-- 更新用戶 -->
    <update id="updateUser">
        UPDATE user
        <set>
            <if test="userName != null">user_name = #{userName},</if>
            <if test="password != null">password = #{password},</if>
            <if test="email != null">email = #{email},</if>
            <if test="age != null">age = #{age},</if>
            <if test="status != null">status = #{status},</if>
            update_time = NOW()
        </set>
        WHERE id = #{id}
    </update>
    <!-- 刪除用戶 -->
    <delete id="deleteUserById">
        DELETE FROM user WHERE id = #{id}
    </delete>
</mapper>

Step 4:創(chuàng)建 Service 層

package com.example.demo.service;

import com.example.demo.entity.User;
import java.util.List;

public interface UserService {
    User getUserById(Long id);
    List<User> getUserList(String userName);
    int addUser(User user);
    int modifyUser(User user);
    int removeUser(Long id);
}
package com.example.demo.service.impl;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public User getUserById(Long id) {
        return userMapper.selectUserById(id);
    }
    
    @Override
    public List<User> getUserList(String userName) {
        return userMapper.selectUserList(userName);
    }
    
    @Override
    public int addUser(User user) {
        return userMapper.insertUser(user);
    }
    
    @Override
    public int modifyUser(User user) {
        return userMapper.updateUser(user);
    }
    
    @Override
    public int removeUser(Long id) {
        return userMapper.deleteUserById(id);
    }
}

Step 5:Controller 層測試

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    @GetMapping("/list")
    public List<User> getUserList(@RequestParam(required = false) String userName) {
        return userService.getUserList(userName);
    }
    
    @PostMapping
    public int addUser(@RequestBody User user) {
        return userService.addUser(user);
    }
    
    @PutMapping
    public int updateUser(@RequestBody User user) {
        return userService.modifyUser(user);
    }
    
    @DeleteMapping("/{id}")
    public int deleteUser(@PathVariable Long id) {
        return userService.removeUser(id);
    }
}

3.4 基于注解的開發(fā)方式

對于簡單的 CRUD 操作,注解方式更加簡潔高效:

package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface UserAnnotationMapper {
    
    @Select("SELECT id, user_name, password, email, age, status, create_time, update_time FROM user WHERE id = #{id}")
    @Results(id = "userResultMap", value = {
        @Result(column = "id", property = "id", id = true),
        @Result(column = "user_name", property = "userName"),
        @Result(column = "create_time", property = "createTime"),
        @Result(column = "update_time", property = "updateTime")
    })
    User selectUserById(@Param("id") Long id);
    
    @SelectProvider(type = UserSqlProvider.class, method = "selectUserList")
    @ResultMap("userResultMap")
    List<User> selectUserList(@Param("userName") String userName);
    
    @Insert("INSERT INTO user (user_name, password, email, age, status, create_time, update_time) " +
            "VALUES (#{userName}, #{password}, #{email}, #{age}, #{status}, NOW(), NOW())")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insertUser(User user);
    
    @Update("UPDATE user SET user_name = #{userName}, password = #{password}, email = #{email}, " +
            "age = #{age}, status = #{status}, update_time = NOW() WHERE id = #{id}")
    int updateUser(User user);
    
    @Delete("DELETE FROM user WHERE id = #{id}")
    int deleteUserById(@Param("id") Long id);
}

對于復雜查詢,可以使用 @SelectProvider 配合 SQL 構建器實現動態(tài) SQL:

package com.example.demo.mapper;

import org.apache.ibatis.jdbc.SQL;

public class UserSqlProvider {
    
    public String selectUserList(String userName) {
        return new SQL() {{
            SELECT("id, user_name, password, email, age, status, create_time, update_time");
            FROM("user");
            if (userName != null && !userName.isEmpty()) {
                WHERE("user_name LIKE CONCAT('%', #{userName}, '%')");
            }
            ORDER_BY("create_time DESC");
        }}.toString();
    }
}

3.5 Mapper 掃描配置

除了在每一個 Mapper 接口上添加 @Mapper 注解,還可以通過 @MapperScan 在配置類中批量掃描:

package com.example.demo.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.demo.mapper")  // 掃描整個 mapper 包
public class MyBatisConfig {
}

四、MyBatis 核心功能深入

4.1 參數傳遞方式

在 MyBatis 中,Mapper 接口方法支持多種參數傳遞方式:

方式一:使用 @Param 注解(推薦)

User selectUser(@Param("id") Long id, @Param("status") Integer status);
<select id="selectUser" resultType="User">
    SELECT * FROM user WHERE id = #{id} AND status = #{status}
</select>

方式二:使用對象參數

int insertUser(User user);
<insert id="insertUser">
    INSERT INTO user (user_name, password) VALUES (#{userName}, #{password})
</insert>

方式三:使用 Map 參數

List<User> selectUserByMap(Map<String, Object> params);

4.2 結果集映射

MyBatis 提供了兩種結果集映射方式:

簡單映射(resultType) :當查詢結果的列名與 Java 對象屬性名一致(或開啟駝峰映射后能匹配)時使用。

復雜映射(resultMap) :支持一對一、一對多等復雜關系映射:

  • 一對一(association) :適用于主表與從表是一對一關系(如:用戶和用戶詳情)
  • 一對多(collection) :適用于主表與從表是一對多關系(如:用戶和訂單列表)
<!-- 一對一關聯映射 -->
<resultMap id="UserWithDetailResultMap" type="User" extends="BaseResultMap">
    <association property="userDetail" javaType="UserDetail" column="id"
                 select="com.example.demo.mapper.UserDetailMapper.selectByUserId"/>
</resultMap>
<!-- 一對多關聯映射 -->
<resultMap id="UserWithOrdersResultMap" type="User" extends="BaseResultMap">
    <collection property="orderList" ofType="Order" column="id"
                select="com.example.demo.mapper.OrderMapper.selectByUserId"/>
</resultMap>

性能提示:對于關聯映射,建議開啟延遲加載(lazyLoadingEnabled=true),避免 N+1 查詢問題。

4.3 動態(tài) SQL(核心精華)

動態(tài) SQL 是 MyBatis 最強大的特性之一,允許根據運行時條件動態(tài)生成 SQL 語句。

常用動態(tài) SQL 標簽詳解

標簽作用示例
<if>條件判斷,滿足條件時包含 SQL 片段<if test="name != null">AND name = #{name}</if>
<choose>多條件分支(類似 switch-case)<choose><when test="age != null">AND age = #{age}</when><otherwise>AND age > 18</otherwise></choose>
<where>智能處理 WHERE 子句,自動去除開頭 AND/OR<where><if test="name != null">AND name = #{name}</if></where>
<set>智能處理 UPDATE 語句,自動去除結尾逗號<set><if test="name != null">name = #{name},</if></set>
<foreach>遍歷集合生成批量操作<foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>
<trim>自定義字符串修剪<trim prefix="WHERE" prefixOverrides="AND">...</trim>
<bind>創(chuàng)建變量并綁定到上下文<bind name="pattern" value="'%' + keyword + '%'" />

批量插入示例

<insert id="batchInsertUsers">
    INSERT INTO user (user_name, password, email) VALUES
    <foreach collection="list" item="user" separator=",">
        (#{user.userName}, #{user.password}, #{user.email})
    </foreach>
</insert>

批量刪除示例

<delete id="batchDeleteUsers">
    DELETE FROM user WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</delete>

動態(tài) SQL 最佳實踐:避免嵌套超過 3 層,使用 <where>、<set> 減少無效字符處理開銷,參數合法性在 Java 層校驗,簡單場景可用 @SelectProvider 替代 XML。

4.4 緩存機制

MyBatis 提供了兩級緩存來提升查詢性能:

一級緩存(Local Cache)

  • 作用域:SqlSession 級別,默認開啟且無法關閉
  • 生命周期:與 SqlSession 一致,執(zhí)行 INSERT/UPDATE/DELETE 操作或調用 commit()、close() 時會清空
  • 適用場景:同一會話內的重復查詢,緩存命中率約 5%

二級緩存(Global Cache)

  • 作用域:Mapper 級別(跨 SqlSession 共享),需手動配置開啟
  • 存儲介質:默認 JVM 內存,可集成 Redis、Ehcache 等
  • 適用場景:多用戶并發(fā)訪問、查詢頻率高且更新不頻繁的數據,緩存命中率可達 90%

啟用二級緩存配置

# application.yml
mybatis:
  configuration:
    cache-enabled: true   # 全局開啟二級緩存
<!-- Mapper XML 中添加 cache 標簽 -->
<mapper namespace="com.example.demo.mapper.UserMapper">
    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="false"/>
</mapper>
// 或者使用注解方式
@CacheNamespace(eviction = LruCache.class, flushInterval = 60000, size = 512)
public interface UserMapper {
}

五、分頁方案

5.1 PageHelper 插件(推薦)

PageHelper 是目前最流行的 MyBatis 分頁插件,只需在查詢前調用 PageHelper.startPage() 即可自動實現物理分頁。

添加依賴

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

使用示例

@Service
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    public PageInfo<User> getUserListByPage(int pageNum, int pageSize, String userName) {
        // 開啟分頁(緊跟在后面的第一個查詢會被分頁)
        PageHelper.startPage(pageNum, pageSize);
        
        // 執(zhí)行查詢
        List<User> userList = userMapper.selectUserList(userName);
        
        // 封裝分頁結果
        return new PageInfo<>(userList);
    }
}

Controller 調用

@GetMapping("/page")
public PageInfo<User> getUserByPage(@RequestParam(defaultValue = "1") int pageNum,
                                     @RequestParam(defaultValue = "10") int pageSize,
                                     @RequestParam(required = false) String userName) {
    return userService.getUserListByPage(pageNum, pageSize, userName);
}

5.2 分頁實現方式對比

MyBatis 主要有五種分頁實現方式:

方式類型原理適用場景性能
RowBounds邏輯分頁查詢全部結果,內存中截取小數據量大數據量易內存溢出
PageHelper物理分頁攔截器動態(tài)添加 LIMIT 子句通用推薦優(yōu)秀
SQL 分頁物理分頁手動編寫 LIMIT/OFFSET簡單場景較好
數組分頁邏輯分頁查全表后 subList 截取小數據量
攔截器分頁物理分頁自定義攔截器統(tǒng)一處理需要統(tǒng)一分頁規(guī)范時優(yōu)秀

最佳實踐:推薦優(yōu)先使用 PageHelper 等物理分頁方式,避免深分頁陷阱。對于超大數據量場景,建議設置 count=false 跳過統(tǒng)計總記錄數以提升性能。

六、性能優(yōu)化指南

6.1 SQL 語句優(yōu)化

  • 精準查詢字段:避免使用 SELECT *,只查詢業(yè)務所需字段
  • 使用 <sql> 標簽:定義可復用字段集合,減少重復書寫
  • 批量操作合并:使用 <foreach> 生成批量插入/更新語句,減少數據庫交互次數
  • 避免 N+1 查詢:合理使用延遲加載或聯表查詢

6.2 緩存策略優(yōu)化

  • 一級緩存:默認開啟,需配合 @Transactional 注解生效,適用于單事務內重復查詢場景
  • 二級緩存:需手動配置開啟,適合多用戶并發(fā)訪問場景。注意:不推薦跨 Mapper 共享熱點數據,易引發(fā)緩存雪崩
  • 分布式緩存:在二級緩存基礎上集成 Redis,通過 @Cacheable 注解實現跨服務緩存一致性

6.3 連接池與監(jiān)控

  • 連接池推薦:HikariCP(Spring Boot 默認)或 Druid,根據業(yè)務負載調整 maximum-pool-sizeconnection-timeout 等參數
  • 監(jiān)控工具:通過 Druid 監(jiān)控 SQL 執(zhí)行時間,識別慢查詢
  • 日志控制:生產環(huán)境關閉 MyBatis 詳細日志(log4j.logger.org.mybatis=ERROR),減少 IO 開銷

七、多數據源配置

在微服務或復雜業(yè)務場景中,多數據源的需求十分常見。推薦使用 dynamic-datasource-spring-boot-starter 開源組件來優(yōu)雅地實現。

7.1 添加依賴

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>4.3.0</version>
</dependency>

7.2 配置文件

spring:
  datasource:
    dynamic:
      primary: master                    # 默認數據源
      strict: false                     # 嚴格模式(匹配不到時拋異常)
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/master_db
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave:
          url: jdbc:mysql://localhost:3306/slave_db
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver

7.3 使用 @DS 注解切換數據源

@Service
@DS("master")                    // 類級別指定默認數據源
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    @DS("slave")                 // 方法級別覆蓋,從從庫讀取
    public User getUserById(Long id) {
        return userMapper.selectUserById(id);
    }
    
    @Override
    @DS("master")                // 寫入操作使用主庫
    public int addUser(User user) {
        return userMapper.insertUser(user);
    }
}

注解優(yōu)先順序:方法級別 > 類級別,dynamic-datasource 還支持讀寫分離、敏感信息加密、分布式事務(基于 Seata)等高級特性。

八、MyBatis-Plus:MyBatis 的超強增強工具

MyBatis-Plus(簡稱 MP)是 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,極大簡化了單表 CRUD 操作。

8.1 核心特性

  • 無侵入:只做增強,不改動 MyBatis 原有邏輯
  • 內置通用 Mapper:提供 BaseMapper 接口,包含常用 CRUD 方法,無需編寫 XML
  • 條件構造器:提供 LambdaQueryWrapper,類型安全的條件構造體驗
  • 代碼生成器:自動生成 Entity、Mapper、Service、Controller 全套代碼
  • 內置分頁插件:基于物理分頁,支持多種數據庫

8.2 代碼生成器

MyBatis-Plus 的代碼生成器 AutoGenerator 可以根據數據庫表結構自動生成整套代碼,極大提升開發(fā)效率。

添加依賴

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.3</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

編寫代碼生成器主類

public class CodeGenerator {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_demo", "root", "123456")
            .globalConfig(builder -> {
                builder.author("your_name")
                       .outputDir(System.getProperty("user.dir") + "/src/main/java")
                       .commentDate("yyyy/MM/dd");
            })
            .packageConfig(builder -> {
                builder.parent("com.example.demo")
                       .entity("entity")
                       .mapper("mapper")
                       .service("service")
                       .serviceImpl("service.impl")
                       .controller("controller");
            })
            .strategyConfig(builder -> {
                builder.addInclude("user")        // 指定要生成的表名
                       .entityBuilder()
                       .enableLombok()            // 開啟 Lombok 支持
                       .idType(IdType.AUTO);      // 主鍵策略
            })
            .templateEngine(new FreemarkerTemplateEngine())
            .execute();
    }
}

九、常見問題與解決方案

9.1 駝峰命名映射問題

如果開啟了 map-underscore-to-camel-case 后仍映射失敗,檢查:

  1. 實體類屬性是否使用了 Lombok(確保有 getter/setter)
  2. 數據庫字段名與屬性名是否真的匹配(如 userName vs user_name

9.2 SQL 注入問題

始終使用 #{}(預編譯參數)而不是 ${}(字符串拼接)。${} 僅用于無法預編譯的場景,如動態(tài)表名、列名。務必對用戶輸入進行嚴格校驗。

9.3 分頁失效問題

如果 PageHelper 分頁不生效,檢查:

  1. PageHelper.startPage() 后是否立即執(zhí)行了查詢
  2. 分頁參數是否被正確傳遞
  3. 是否有其他攔截器干擾

9.4 延遲加載不生效

確保在配置文件中開啟 lazyLoadingEnabled=true,且關聯查詢使用 select 屬性指定子查詢。

十、總結與展望

本文從 MyBatis 的核心概念、架構原理入手,詳細講解了 Spring Boot 整合 MyBatis 的兩種主流方式(XML 與注解),深入剖析了動態(tài) SQL、緩存機制、分頁方案、性能優(yōu)化、多數據源配置等進階內容,最后介紹了 MyBatis-Plus 這個強大的增強工具。

在實際項目開發(fā)中,建議根據場景選擇合適的組合:

  • 簡單項目:Spring Boot + MyBatis(注解方式)+ PageHelper
  • 復雜項目:Spring Boot + MyBatis(XML 方式)+ MyBatis-Plus(僅使用增強功能)
  • 極速開發(fā):Spring Boot + MyBatis-Plus + 代碼生成器

MyBatis 以其靈活性和高性能,在國內 Java 社區(qū)擁有極其龐大的用戶基礎。掌握 MyBatis,不僅是一項必備的 Java 開發(fā)技能,更是通向高級工程師道路上的一塊重要基石。希望本文能幫助你全面掌握 MyBatis 的核心知識,在實際項目中游刃有余!

以上就是從入門到精通詳解SpringBoot整合MyBatis的全攻略的詳細內容,更多關于SpringBoot整合MyBatis的資料請關注腳本之家其它相關文章!

相關文章

  • Java堆轉儲文件之1.6G大文件處理完整指南

    Java堆轉儲文件之1.6G大文件處理完整指南

    堆轉儲文件是優(yōu)化、分析內存消耗的重要工具,這篇文章主要介紹了Java堆轉儲文件之1.6G大文件處理的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-07-07
  • Java 替換word文檔文字并指定位置插入圖片

    Java 替換word文檔文字并指定位置插入圖片

    這篇文章主要介紹了Java 替換word文檔文字,指定位置插入圖片功能,本文通過實例代碼給大家講解,需要的朋友可以參考下
    2018-02-02
  • java?數組實現學生成績統(tǒng)計教程

    java?數組實現學生成績統(tǒng)計教程

    這篇文章主要介紹了java?數組實現學生成績統(tǒng)計教程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 如何基于java實現解壓ZIP TAR等文件

    如何基于java實現解壓ZIP TAR等文件

    這篇文章主要介紹了如何基于java實現解壓ZIP TAR等文件,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • 詳解SpringBoot配置連接池

    詳解SpringBoot配置連接池

    本篇文章主要詳解SpringBoot配置連接池,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • 詳細總結Java for循環(huán)的那些坑

    詳細總結Java for循環(huán)的那些坑

    在平常寫代碼的過程中循環(huán)是不可避免的,雖然for的語法并不復雜,但是在開發(fā)中還是會遇到一些坑,雖然大部分的坑都是自己的騷操作導致的.今天來總結一下for循環(huán)在開發(fā)中可能遇到的坑,不要在同樣的問題上再次犯錯.需要的朋友可以參考下
    2021-05-05
  • 從Android源碼剖析Intent查詢匹配的實現

    從Android源碼剖析Intent查詢匹配的實現

    這篇文章主要介紹了從Android源碼剖析Intent查詢匹配的實現,Intent部分的源碼為Java代碼,需要的朋友可以參考下
    2015-07-07
  • Java 實現貪吃蛇游戲的示例

    Java 實現貪吃蛇游戲的示例

    這篇文章主要介紹了Java 如何實現貪吃蛇游戲,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下
    2021-03-03
  • SpringBoot開發(fā)實戰(zhàn)系列之動態(tài)定時任務

    SpringBoot開發(fā)實戰(zhàn)系列之動態(tài)定時任務

    在我們日常的開發(fā)中,很多時候,定時任務都不是寫死的,而是寫到數據庫中,從而實現定時任務的動態(tài)配置,下面這篇文章主要給大家介紹了關于SpringBoot開發(fā)實戰(zhàn)系列之動態(tài)定時任務的相關資料,需要的朋友可以參考下
    2021-08-08
  • 深入理解Thread.sleep(0)的作用

    深入理解Thread.sleep(0)的作用

    本文主要介紹了深入理解Thread.sleep(0)的作用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-09-09

最新評論

大连市| 镇巴县| 循化| 凤台县| 惠安县| 岱山县| 弥渡县| 城步| 通山县| 西畴县| 阜康市| 清徐县| 土默特右旗| 万盛区| 永胜县| 松潘县| 珠海市| 肇庆市| 垦利县| 静乐县| 山阴县| 仁布县| 郴州市| 开化县| 安化县| 横山县| 莲花县| 伊金霍洛旗| 随州市| 腾冲县| 淮安市| 报价| 江油市| 顺昌县| 贵州省| 文成县| 沙湾县| 永安市| 永昌县| 赤峰市| 郓城县|