MyBatis中的十個寶藏技巧!
前言
說到 MyBatis,很多小伙伴都會用,但未必用得“驚艷”。
實際上,這個輕量級的持久層框架還有很多隱藏的“寶藏技巧”。
如果你能掌握這些技巧,不但能讓開發(fā)更高效,還能避免掉入一些常見的“坑”。
今天就從淺入深,分享 10 個讓人眼前一亮的 MyBatis 開發(fā)技巧,每一個都配上具體的場景和代碼示例,務求通俗易懂,希望對你會有所幫助。
1. 靈活使用動態(tài) SQL
很多小伙伴在寫 SQL 的時候,喜歡直接用拼接字符串的方式,比如:
String sql = "SELECT * FROM user WHERE 1=1";
if (name != null) {
sql += " AND name = '" + name + "'";
}
這種寫法不僅麻煩,而且安全性很差(容易引發(fā) SQL 注入)。
MyBatis 的動態(tài) SQL 是專門為解決這種問題設計的,你可以用 if、choose、foreach 等標簽來動態(tài)構造 SQL。
示例:動態(tài)條件查詢
<select id="findUser" resultType="User">
SELECT * FROM user
WHERE 1=1
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</select>
這個代碼的好處是,SQL 邏輯清晰,不會因為某個參數(shù)為空就導致整個 SQL 報錯。
2. 善用 resultMap 自定義結果映射
有些小伙伴會遇到這樣的問題:數(shù)據(jù)庫表字段是下劃線命名,但 Java 對象是駝峰命名。比如 user_name 對應 userName。如果直接用默認的 resultType,MyBatis 是無法自動映射的。
這個時候,用 resultMap 就能完美解決。
示例:自定義結果映射
<resultMap id="userResultMap" type="User">
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
<result column="age" property="age"/>
</resultMap>
<select id="getUserById" resultMap="userResultMap">
SELECT id, user_name, age FROM user WHERE id = #{id}
</select>
有了 resultMap,再復雜的字段映射都可以輕松搞定。
3. 利用 foreach 實現(xiàn)批量操作
有些小伙伴可能會遇到這種需求:傳入一個 ID 列表,查詢所有匹配的用戶信息。如果用拼接字符串的方式生成 IN
條件,不但代碼丑,還容易踩坑。
MyBatis 提供了 foreach 標簽,可以優(yōu)雅地處理這種場景。
示例:批量查詢
<select id="findUsersByIds" resultType="User">
SELECT * FROM user WHERE id IN
<foreach item="id" collection="idList" open="(" separator="," close=")">
#{id}
</foreach>
</select>
傳入的 idList 是一個 List 或數(shù)組,MyBatis 會自動幫你展開為 IN (1, 2, 3) 這樣的格式,完全不用擔心語法問題。
4. MyBatis-Plus 的分頁功能
很多小伙伴在做分頁的時候,習慣自己寫 LIMIT 的 SQL,這樣不僅麻煩,還容易出錯。
其實,用 MyBatis-Plus 的分頁插件能省不少事。
示例:MyBatis-Plus 分頁功能
Page<User> page = new Page<>(1, 10); // 第 1 頁,每頁 10 條
IPage<User> userPage = userMapper.selectPage(page, null);
System.out.println("總記錄數(shù):" + userPage.getTotal());
System.out.println("當前頁數(shù)據(jù):" + userPage.getRecords());
只需引入分頁插件,就能輕松完成分頁操作,簡直不要太爽。
5. 使用 @Mapper的接口代理
有些小伙伴覺得 XML 文件太多太麻煩,其實 MyBatis 支持純注解的開發(fā)模式,尤其是對于簡單的 SQL,非常方便。
示例:注解方式查詢
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(int id);
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
void addUser(User user);
}
用這種方式,可以完全省掉 XML 配置,代碼更加簡潔。
6. 二級緩存
MyBatis 內置了一級緩存(SqlSession 范圍內),但對于多次查詢的場景,可以開啟二級緩存來提升性能。
示例:開啟二級緩存
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
<mapper namespace="com.example.mapper.UserMapper">
<cache/>
<select id="getUserById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
開啟二級緩存后,同一個 Mapper 下的查詢會自動命中緩存,大幅提高性能。
7. 動態(tài)表名切換
有些多租戶系統(tǒng)需要在運行時切換表名,比如按租戶分表。這種情況下,可以用 MyBatis 的動態(tài) SQL 特性來實現(xiàn)。
示例:動態(tài)表名
<select id="getDataFromDynamicTable" resultType="Map">
SELECT * FROM ${tableName} WHERE id = #{id}
</select>
在調用時傳入 tableName 參數(shù),MyBatis 會動態(tài)替換表名。
8. 用 typeHandler 自定義類型處理
有些小伙伴可能遇到過這種場景:數(shù)據(jù)庫存的是 1/0,但在代碼里想用 true/false 表示。
這種情況可以通過自定義 typeHandler 來實現(xiàn)。
示例:自定義 TypeHandler
@MappedTypes(Boolean.class)
@MappedJdbcTypes(JdbcType.INTEGER)
public class BooleanTypeHandler extends BaseTypeHandler<Boolean> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter ? 1 : 0);
}
@Override
public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getInt(columnName) == 1;
}
}
在 MyBatis 配置中注冊這個 typeHandler,就可以實現(xiàn)自動類型轉換了。
9. 日志調試,快速排查問題
開發(fā)中經(jīng)常需要排查 SQL 執(zhí)行的問題,這時 MyBatis 的日志功能非常好用。
通過配置,可以輕松打印出完整的 SQL 和參數(shù)。
示例:開啟日志
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
日志會輸出類似下面的內容:
==> Preparing: SELECT * FROM user WHERE id = ?
==> Parameters: 1(Integer)
<== Total: 1
有了這些日志,排查問題再也不頭疼了。
10. 多數(shù)據(jù)源支持
當系統(tǒng)需要連接多個數(shù)據(jù)庫時,可以通過 MyBatis 的多數(shù)據(jù)源配置輕松搞定。
示例:配置多數(shù)據(jù)源
@Configuration
@MapperScan(basePackages = "com.example.mapper", sqlSessionTemplateRef = "sqlSessionTemplate1")
public class DataSourceConfig1 {
@Bean(name = "dataSource1")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "sqlSessionFactory1")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource1") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "sqlSessionTemplate1")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
通過類似的配置,就可以輕松切換多個數(shù)據(jù)源。
總結
MyBatis 的魅力在于簡單、高效,但很多時候我們用得太“基礎”,沒有發(fā)揮它的全部潛力。
希望這 10 個技巧能幫你更高效地使用 MyBatis,也讓你的代碼看起來更“驚艷”。