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

Spring 整合 MyBatis 三大核心方案:MapperFactoryBean、SqlSessionTemplate、SqlSessionDaoSupport

     編輯:Java 相關知識

Spring + MyBatis 整合三種經典模式深度解析

MyBatis-Spring 整合包提供了多種 DAO 實現模式,本文系統講解三大核心方案的配置原理、代碼結構、優缺點對比及選型建議,基於 MyBatis-Spring 2.0+、Spring 5.x/6.x 環境驗證。

一、核心依賴與基礎配置

1.1 Maven 依賴


<dependencies>
    <!-- Spring 核心 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.30</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.30</version>
    </dependency>
    
    <!-- MyBatis 核心 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.16</version>
    </dependency>
    
    <!-- 整合包(關鍵) -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.7</version>
    </dependency>
    
    <!-- 數據源/連接池 -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version>
    </dependency>
</dependencies>

1.2 通用數據源與 SqlSessionFactory 配置


@Configuration
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {
    
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setDriverClassName(driver);
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        return new HikariDataSource(config);
    }
    
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        // 可選:指定 MyBatis 總配置文件
        factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
        // 可選:指定 Mapper 掃描路徑
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
            .getResources("classpath*:mapper/**/*.xml"));
        // 可選:類型別名包
        factoryBean.setTypeAliasesPackage("com.example.entity");
        return factoryBean.getObject();
    }
    
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    
    // 掃描 Mapper 接口(推薦方式,替代方案一的手動註冊)
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("com.example.mapper");
        configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        return configurer;
    }
}

二、方案一:MapperFactoryBean(接口代理模式)

特點:無需寫 XML,使用註解定義 SQL,適合簡單 CRUD。

2.1 Mapper 接口定義


@Mapper // 或由 MapperScannerConfigurer 掃描
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(@Param("id") Long id);
    
    @Insert("INSERT INTO users(username, email) VALUES(#{username}, #{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);
    
    @Update("UPDATE users SET username=#{username}, email=#{email} WHERE id=#{id}")
    int update(User user);
    
    @Delete("DELETE FROM users WHERE id = #{id}")
    int deleteById(Long id);
    
    @Select("SELECT * FROM users WHERE username LIKE CONCAT('%', #{keyword}, '%')")
    List searchByName(@Param("keyword") String keyword);
}

2.2 Service 層注入使用


@Service
@Transactional
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper; // 構造器注入
    
    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
    
    @Override
    public User getUser(Long id) {
        return userMapper.findById(id);
    }
    
    @Override
    public User createUser(User user) {
        userMapper.insert(user);
        return user; // 回填自增 ID
    }
}

2.3 優缺點分析

優點缺點
無 XML 文件,代碼集中複雜 SQL 可讀性差,難以維護
重構友好,IDE 支持跳轉動態 SQL 編寫繁瑣(需用 Script 標籤)
適合微服務輕量級服務DBA 難以獨立優化 SQL

三、方案二:SqlSessionTemplate(模板方法模式)

特點:傳統 XML Mapper + 手動調用 SqlSession 方法,靈活控制。

3.1 XML Mapper 文件


<!-- resources/mapper/UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <resultMap id="userMap" type="User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="email" column="email"/>
        <result property="createTime" column="create_time"/>
    </resultMap>
    
    <select id="findById" resultMap="userMap">
        SELECT * FROM users WHERE id = #{id}
    </select>
    
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO users(username, email) VALUES(#{username}, #{email})
    </insert>
</mapper>

3.2 DAO 實現類


@Repository
public class UserDaoImpl implements UserDao {
    private final SqlSessionTemplate sqlSession;
    
    public UserDaoImpl(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }
    
    @Override
    public User findById(Long id) {
        // 完全限定名:namespace + id
        return sqlSession.selectOne("com.example.mapper.UserMapper.findById", id);
    }
    
    @Override
    public void insert(User user) {
        sqlSession.insert("com.example.mapper.UserMapper.insert", user);
    }
    
    @Override
    public List findByCondition(UserQuery query) {
        return sqlSession.selectList("com.example.mapper.UserMapper.findByCondition", query);
    }
}

3.3 優缺點分析

優點缺點
SQL 與代碼分離,DBA 友好字符串硬編碼 namespace+id,重構易出錯
支持複雜動態 SQL樣板代碼多(selectOne/insert/update/delete)
可精確控制事務邊界需手動管理 SqlSession 生命周期(模板已處理)

四、方案三:SqlSessionDaoSupport(繼承支持類)

特點:繼承框架基類,通過 getSqlSession() 獲取模板,最傳統方式。

4.1 DAO 實現


@Repository
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
    
    // 注入 SqlSessionFactory 或 SqlSessionTemplate
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }
    
    @Override
    public User findById(Long id) {
        return getSqlSession().selectOne("com.example.mapper.UserMapper.findById", id);
    }
    
    @Override
    public void insert(User user) {
        getSqlSession().insert("com.example.mapper.UserMapper.insert", user);
    }
}

4.2 Spring XML 配置(非註解方式)


<bean id="userDao" class="com.example.dao.UserDaoImpl">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

五、現代最佳實踐:Mapper 掃描 + 注解/XML 混合

推薦配置:


@Configuration
@MapperScan(basePackages = "com.example.mapper", 
            sqlSessionFactoryRef = "sqlSessionFactory")
public class MyBatisConfig {
    // SqlSessionFactory 配置同上
}

5.1 混合使用策略

  • 簡單 CRUD:Mapper 接口 + 註解(@Select/@Insert 等)
  • 複雜查詢:Mapper 接口 + XML 文件(同名同目錄)
  • 動態 SQL:XML 文件(<where>/<if>/<choose>)
  • 存儲過程/特殊 SQL:XML + @SelectProvider 類

5.2 Mapper 接口示例(混合模式)


@Mapper
public interface UserMapper {
    // 簡單查詢用註解
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);
    
    // 複雜查詢對應 XML:UserMapper.xml 中定義 findActiveUsers
    List findActiveUsers(@Param("since") LocalDateTime since);
    
    // 批量插入用註解
    @Insert("")
    int batchInsert(@Param("list") List users);
}

六、事務管理整合


@Configuration
@EnableTransactionManagement
public class TxConfig {
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

// Service 使用
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
    // MyBatis-Spring 自動參與 Spring 事務
    // SqlSessionTemplate 綁定當前線程事務
}

七、方案選型決策表

場景推薦方案關鍵配置
新項目、微服務、簡單業務方案一 + MapperScan註解為主,XML 為輔
傳統項目遷移、DBA 主導 SQL方案二/三 + XMLSqlSessionTemplate 注入
複雜報表、動態 SQL 多方案二 + XML手動調用 selectList
需精確控制 SqlSession 生命周期方案二sqlSessionFactory.openSession()
現代 Spring Boot 項目MyBatis-Spring-Boot-Starter自動配置,零 XML

八、常見問題排查

  1. Mapper 接口無法注入:檢查 @MapperScan 包路徑、接口是否有 @Mapper、編譯輸出目錄
  2. XML 文件未生效:mapperLocations 路徑匹配、namespace 全限定名一致、resources 目錄打包
  3. 事務不生效:@EnableTransactionManagement、DataSourceTransactionManager、方法非 private、異常類型匹配
  4. 多數據源:配置多個 SqlSessionFactory、MapperScan 指定 sqlSessionFactoryRef

理解三種方案的本質區別:方案一是接口代理(JDK 動態代理),方案二/三是模板委託。現代開發推薦 @MapperScan + 註解/XML 混合,兼顧開發效率與 SQL 可維護性。

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