MyBatis (原 iBATIS) 作為半自動 ORM 框架,與 Spring 整合是企業級開發常見技術棧。本文系統梳理整合配置全流程,重點講解註解驅動開發模式與 SqlBuilder 動態 SQL 構建。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.0.1</version>
</dependency>
僅保留 Settings 與 TypeAliases,其餘 (DataSource、Transaction 等) 交由 Spring 管理:
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="autoMappingBehavior" value="FULL"/>
<setting name="defaultExecutorType" value="BATCH"/>
<setting name="defaultStatementTimeout" value="25000"/>
</settings>
<typeAliases>
<typeAlias alias="TestBean" type="com.wotao.taotao.persist.test.dataobject.TestBean"/>
</typeAliases>
<!-- 註解模式下可省略 mappers 配置 -->
</configuration>
<bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driver.class}"/>
<property name="jdbcUrl" value="${db.url}"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="initialPoolSize" value="5"/>
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="20"/>
<property name="maxStatements" value="100"/>
<property name="maxIdleTime" value="3600"/>
<property name="acquireIncrement" value="2"/>
<property name="acquireRetryAttempts" value="10"/>
<property name="acquireRetryDelay" value="600"/>
<property name="checkoutTimeout" value="10000"/> <!-- 關鍵:防止資料庫響應慢導致誤判超時 -->
</bean>
<bean id="testSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:configuration.xml"/> <property name="dataSource" ref="testDataSource"/> </bean>
<bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="testSqlSessionFactory"/> <property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper"/> </bean>
無需配置 SqlSessionTemplate,MapperFactoryBean 直接代理 Mapper 接口。
@CacheNamespace(size = 512)
public interface TestMapper {
@SelectProvider(type = TestSqlProvider.class, method = "getSql")
@Options(useCache = true, flushCache = false, timeout = 10000)
@Results({
@Result(id = true, property = "id", column = "test_id", javaType = String.class, jdbcType = JdbcType.VARCHAR),
@Result(property = "testText", column = "test_text", javaType = String.class, jdbcType = JdbcType.VARCHAR)
})
TestBean get(@Param("id") String id);
@SelectProvider(type = TestSqlProvider.class, method = "getAllSql")
@Options(useCache = true, flushCache = false, timeout = 10000)
@Results({ ... })
List<TestBean> getAll();
@SelectProvider(type = TestSqlProvider.class, method = "getByTestTextSql")
@Options(useCache = true, flushCache = false, timeout = 10000)
@ResultMap("getByTestText") // 複雜映射引用 XML resultMap
List<TestBean> getByTestText(@Param("testText") String testText);
@InsertProvider(type = TestSqlProvider.class, method = "insertSql")
@Options(flushCache = true, timeout = 20000)
void insert(@Param("testBean") TestBean testBean);
@UpdateProvider(type = TestSqlProvider.class, method = "updateSql")
@Options(flushCache = true, timeout = 20000)
void update(@Param("testBean") TestBean testBean);
@DeleteProvider(type = TestSqlProvider.class, method = "deleteSql")
@Options(flushCache = true, timeout = 20000)
void delete(@Param("id") String id);
}
| 註解 | 用途 |
|---|---|
@CacheNamespace | 命名空間級二級快取,size=512 條目 |
@SelectProvider | 指定 SQL 提供類/方法,分離 SQL 與介面 |
@Options | 查詢選項:快取、刷新、超時 |
@Results / @Result | 結果映射:欄位→屬性、主鍵標記、類型轉換 |
@ResultMap | 引用 XML 定義的 <resultMap>,支援嵌套/鑑別器 |
@Param | 參數命名,SQL 中用 #{paramName} 引用 |
@InsertProvider/@UpdateProvider/@DeleteProvider | 增刪改 SQL 提供者 |
<mapper namespace="com.wotao.taotao.persist.test.mapper.TestMapper">
<resultMap id="getByTestText" type="TestBean">
<id property="id" column="test_id" javaType="string" jdbcType="VARCHAR"/>
<result property="testText" column="test_text" javaType="string" jdbcType="VARCHAR"/>
</resultMap>
</mapper>
注意:namespace 必須為 Mapper 接口全限定名,id 與 @ResultMap value 一致。
public class TestSqlProvider {
private static final String TABLE_NAME = "test";
public String getSql(Map<String, Object> params) {
String uid = (String) params.get("id");
BEGIN();
SELECT("test_id, test_text");
FROM(TABLE_NAME);
if (uid != null) WHERE("test_id = #{id,javaType=string,jdbcType=VARCHAR}");
return SQL();
}
public String getAllSql() {
BEGIN(); SELECT("test_id, test_text"); FROM(TABLE_NAME); return SQL();
}
public String getByTestTextSql(Map<String, Object> params) {
String tText = (String) params.get("testText");
BEGIN(); SELECT("test_id, test_text"); FROM(TABLE_NAME);
if (tText != null) WHERE("test_text like #{testText,javaType=string,jdbcType=VARCHAR}");
return SQL();
}
public String insertSql() {
BEGIN(); INSERT_INTO(TABLE_NAME);
VALUES("test_id", "#{testBean.id,javaType=string,jdbcType=VARCHAR}");
VALUES("test_text", "#{testBean.testText,javaType=string,jdbcType=VARCHAR}");
return SQL();
}
public String updateSql() {
BEGIN(); UPDATE(TABLE_NAME);
SET("test_text = #{testBean.testText,javaType=string,jdbcType=VARCHAR}");
WHERE("test_id = #{testBean.id,javaType=string,jdbcType=VARCHAR}");
return SQL();
}
public String deleteSql() {
BEGIN(); DELETE_FROM(TABLE_NAME);
WHERE("test_id = #{id,javaType=string,jdbcType=VARCHAR}");
return SQL();
}
}
BEGIN() 清理線程局部變量,SELECT/FROM/WHERE/SET/VALUES 等靜態方法鏈式構建 SQL,SQL() 返回最終字串。支援 JOIN、GROUP_BY、ORDER_BY 等進階子句。
@Repository("testBaseDAO")
public class TestBaseDAO {
private TestMapper testMapper;
@Autowired
public void setTestMapper(@Qualifier("testMapper") TestMapper testMapper) {
this.testMapper = testMapper;
}
// 業務方法調用 testMapper.get(id) 等
}
MapperFactoryBean 直接代理 Mapper 介面,無需 SqlSessionTemplateresultMap + @ResultMap 混合SqlBuilder 讓動態 SQL 保持類型安全與可讀性,避免字串拼接錯誤@Param) 讓 SQL 參數引用更清晰,不依賴順序