MyBatis 採用「配置驅動」架構,核心組件協作流程:
配置文件(mybatis-config.xml)
→ SqlSessionFactoryBuilder
→ SqlSessionFactory (單例,線程安全)
→ SqlSession (非線程安全,請求級)
→ Mapper 接口代理 / 直接執行 SQL
→ 結果映射 (resultType/resultMap)
→ 返回實體對象
public interface BlogMapper {
@Select("select * from t_blog where id = #{id}")
Blog selectBlog(int id);
}
<mapper namespace="com.example.BlogMapper">
<select id="selectBlog" parameterType="int" resultType="Blog">
select * from t_blog where id = #{id}
</select>
</mapper>
Blog blog = session.selectOne("com.example.BlogMapper.selectBlog", 101);
<!-- 數據源 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.example.model"/>
</bean>
<!-- 掃描 Mapper 接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
@Service
public class BlogServiceImpl implements BlogService {
@Autowired
private BlogMapper blogMapper; // 自動注入 Mapper 代理
public void doSomething(int blogId) {
Blog blog = blogMapper.selectBlog(blogId);
// 事務由 Spring 管理(@Transactional)
}
}
@MapperScan("com.example.mapper")
@SpringBootApplication
public class Application { ... }
// application.yml
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.model
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
// 1. 從輸入流構建(最常用)
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
// 2. 指定環境
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is, "production");
// 3. 覆蓋配置屬性
Properties props = new Properties();
props.setProperty("jdbc.url", "jdbc:mysql://prod:3306/db");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is, props);
// 4. 從 Configuration 對象構建(程序化配置)
Configuration config = new Configuration();
config.setEnvironment(new Environment("dev", new JdbcTransactionFactory(), dataSource));
config.addMapper(BlogMapper.class);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);
public class SqlSessionFactoryHolder {
private static final SqlSessionFactory FACTORY;
static {
try (InputStream is = Resources.getResourceAsStream("mybatis-config.xml")) {
FACTORY = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
public static SqlSessionFactory getSqlSessionFactory() {
return FACTORY;
}
}
<configuration>
<properties resource="jdbc.properties"/> <!-- 外部屬性 -->
<settings> <!-- 運行時行為 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<typeAliases> <!-- 類型別名 -->
<package name="com.example.model"/>
</typeAliases>
<typeHandlers> <!-- 類型處理器 -->
<typeHandler handler="com.example.handler.JsonTypeHandler"/>
</typeHandlers>
<environments default="development"> <!-- 多環境 -->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED"> <!-- 連接池 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers> <!-- 映射器註冊 -->
<package name="com.example.mapper"/>
</mappers>
</configuration>
| 類型 | 特點 | 適用場景 |
|---|---|---|
| UNPOOLED | 每次打開/關閉連接,無池化 | 簡單應用、測試環境 |
| POOLED | 內置連接池,配置豐富 | 生產環境標準選擇 |
| JNDI | 容器管理數據源(Tomcat/JBoss/WebLogic) | Java EE 容器部署 |
JDBC:使用 JDBC 原生提交/回滾,MyBatis 管理事務邊界MANAGED:不提交/回滾,交給容器(Spring/JTA)管理,需設 closeConnection="false"// 默認:事務不自動提交,連接來自配置數據源,SIMPLE 執行器
SqlSession session = factory.openSession();
// 顯式控制
SqlSession session = factory.openSession(ExecutorType.REUSE); // 復用預處理語句
SqlSession session = factory.openSession(ExecutorType.BATCH); // 批量更新
SqlSession session = factory.openSession(true); // 自動提交
SqlSession session = factory.openSession(Connection conn); // 使用外部連接
SqlSession session = factory.openSession(TransactionIsolationLevel.READ_COMMITTED);
| 類型 | 特點 | 適用場景 |
|---|---|---|
| SIMPLE | 每條語句創建新 PreparedStatement | 通用場景,默認 |
| REUSE | 復用 PreparedStatement | 高頻重複 SQL,減少解析開銷 |
| BATCH | 批量執行 update/insert/delete | 大批量寫入,需手動 flushStatements() |
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
// Mapper 接口方式(推薦)
Mapper mapper = session.getMapper(Mapper.class);
mapper.insert(entity);
resultType:簡單映射,列名=屬性名(或開啟駝峰轉換)resultMap:複雜映射(列名不匹配、關聯對象、嵌套結果、構造方法注入)<insert id="insertBlog" parameterType="Blog" useGeneratedKeys="true" keyProperty="id">
insert into t_blog(title, content, owner) values(#{title}, #{content}, #{owner})
</insert>
<!-- 錯誤:LIKE "%"#{title}"%" -->
<!-- 正確:CONCAT 或字符串拼接 -->
<select id="fuzzyQuery" resultType="Blog" parameterType="string">
select * from t_blog where title LIKE CONCAT('%', #{title}, '%')
</select>
com.example
├── model
│ └── Blog.java // 實體類
├── mapper
│ ├── BlogMapper.java // 接口(含注解映射)
│ └── BlogMapper.xml // XML 映射
├── service
│ └── BlogServiceImpl.java // 業務層
├── test
│ ├── TestXmlMapper.java // XML 映射測試
│ ├── TestAnnotationMapper.java // 注解映射測試
│ └── TestApiDirect.java // API 直接調用測試
└── util
└── MyBatisUtil.java // SqlSessionFactory 工具
CREATE TABLE t_blog (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) DEFAULT NULL,
content VARCHAR(255) DEFAULT NULL,
owner VARCHAR(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
MyBatis 核心功能體系包含:多樣的映射方式(注解/XML/API)、無縫 Spring 整合、靈活的 SqlSessionFactory 構建、豐富的配置體系(屬性、設置、類型別名、環境、映射器)、多模式 SqlSession(SIMPLE/REUSE/BATCH)、強大的結果映射(resultType/resultMap/主鍵回填)。掌握這些核心知識點,配合動態 SQL、緩存、插件機制等進階特性,能構建出高性能、可維護的持久層架構。