15 种超赞的 MyBatis 写法

125 阅读5分钟

MyBatis 是一款功能强大的 ORM 框架,它通过提供灵活的 SQL 映射和动态 SQL 生成方式,帮助开发者在 Java 程序中高效地与数据库进行交互。在 MyBatis 中,有许多技巧和写法可以让我们更好地管理和优化数据库操作。本文将介绍 15 种常见且实用的 MyBatis 写法,提升代码质量与性能,并以代码实例为基础进行解释,最后进行逻辑分析。

1.使用动态 SQL 生成复杂查询

动态 SQL 允许根据传入的参数生成不同的 SQL 语句,避免了复杂条件下的 SQL 拼接问题。

<select id="selectUsersByCondition" parameterType="map" resultType="User">   
   SELECT * FROM users WHERE 1=1    
   <if test="username != null">
       AND username = #{username}
   </if>    
   <if test="age != null">
       AND age = #{age}
   </if>    
   <if test="status != null">
      AND status = #{status}
   </if>
</select>

逻辑分析:动态 SQL 提供了灵活的查询条件,使得 SQL 语句能够根据需求动态变化,减少了冗余的代码。

2. 使用foreach实现批量操作

对于批量查询或批量插入,可以使用 foreach 标签来生成批量 SQL。

  <insert id="batchInsert" parameterType="list">    
      INSERT INTO users (username, age)   VALUES    
      <foreach collection="list" item="user" separator=",">        
      (#{user.username}, #{user.age})    
      </foreach>
  </insert>

逻辑分析:foreach 提供了一种简便的方式来处理批量数据的插入或更新,减少了多次调用的性能消耗。

3. 使用resultMap映射复杂结果

当查询返回的列与实体类的字段名称不一致时,resultMap 可以帮忙进行映射。

   
   <resultMap id="userResultMap" type="User">    
     <id property="id" column="user_id"/>    
     <result property="username" column="user_name"/>    
     <result property="age" column="user_age"/>
   </resultMap>

   <select id="selectUser" resultMap="userResultMap">    
      SELECT user_id, user_name, user_age FROM users WHERE user_id = #{id}
   </select>

逻辑分析:resultMap 使得 SQL 结果与 Java 对象之间的映射变得更加灵活和清晰,适用于复杂的查询结果。

4. 分页查询的实现

使用分页插件(如 MyBatis-Plus 或 PageHelper)简化分页查询。

  Page<User> page = new Page<>(1, 10); // 第 1 页,10 条数据
  List<User> users = userMapper.selectPage(page, new QueryWrapper<>());

逻辑分析:分页插件自动处理分页逻辑,减少了手动拼接 LIMIT 和 OFFSET 的繁琐工作,提升了分页查询的效率。

5. 处理一对多关系

使用 resultMap 的 collection 标签处理一对多关系。

   <resultMap id="userWithOrders" type="User"> 
      <id property="id" column="user_id"/>
      <result property="username" column="user_name"/> 
      <collection property="orders" ofType="Order"> 
         <id property="id" column="order_id"/>
         <result property="amount" column="order_amount"/> 
      </collection>
  </resultMap>
  
  <select id="selectUserWithOrders" resultMap="userWithOrders">
     SELECT u.user_id, u.user_name, o.order_id, o.order_amount  
     FROM users u 
     LEFT JOIN orders o ON u.user_id = o.user_id  
  </select>

逻辑分析:collection 标签帮助我们实现了一对多的查询关系,自动将结果封装到父对象中,方便后续处理。

6. 使用@Mapper注解与XML配合

通过 @Mapper 注解简化接口的配置,并与 XML 配合使用。


@Mapper
public interface UserMapper {    
    List<User> selectUsersByCondition(Map<String, Object> params);
}

<select id="selectUsersByCondition" parameterType="map" resultType="User">    
   SELECT * FROM users WHERE username = #{username} AND age = #{age}
</select>

逻辑分析:@Mapper 注解让接口与 SQL 映射文件更自然地结合,提高了代码的可维护性与清晰度。

7. 批量更新操作

通过 foreach 批量更新数据,提高执行效率。

<update id="batchUpdateUsers" parameterType="list">  
    <foreach collection="list" item="user" separator=";">        
       UPDATE users  SET username = #{user.username}, age = #{user.age}        
       WHERE id = #{user.id}   
    </foreach>
</update>

逻辑分析:foreach 的使用能够有效地减少数据库操作的次数,批量更新带来更高的性能。

8. 使用bind处理复杂表达式

使用 bind 处理复杂的字符串拼接和计算逻辑。

   <bind name="pattern" value="'%' + keyword + '%'"/>
    <select id="selectUsersByKeyword" resultType="User">
       SELECT * FROM users WHERE username LIKE #{pattern}
    </select>

逻辑分析:bind 标签帮助我们在 SQL 中进行表达式计算,减少了 Java 中的拼接操作,使 SQL 更加简洁。

9. 自定义类型处理器

当 Java 类型与数据库类型不一致时,可以自定义类型处理器。

@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(CustomType.class)
public class CustomTypeHandler extends BaseTypeHandler<CustomType> {    
   
   @Override    
   public void setNonNullParameter(PreparedStatement ps, int i, CustomType parameter, JdbcType      jdbcType) throws SQLException {        
       ps.setString(i, parameter.toString());    
   }
   
   @Override    
   public CustomType getNullableResult(ResultSet rs, String columnName) throws SQLException {           return new CustomType(rs.getString(columnName));    
   }}

逻辑分析:自定义类型处理器解决了数据库和 Java 类型之间的不匹配问题,使得转换变得更加灵活。

10. 实现逻辑删除

使用逻辑删除替代物理删除,保留数据历史。

<update id="deleteUser" parameterType="int">   
    UPDATE users SET deleted = 1 WHERE id = #{id}
</update>

逻辑分析:逻辑删除是一种常见的方案,可以在不删除数据的情况下,标记数据为已删除,便于后续恢复。

11. 分表策略

通过动态生成表名来实现分表查询。

   <select id="selectFromTable" resultType="User">
       SELECT * FROM ${tableName}  WHERE id  =  #{id} 
   </select>

逻辑分析:分表策略能够提升数据库性能,适用于海量数据的场景。使用动态 SQL 实现表名切换时,需要特别注意 SQL 注入的防范。

12. 复用SQL片段

通过 sql 标签重用 SQL 片段,减少重复代码。

  <sql id="baseUserColumns"> 
   id, username, age, email 
  </sql>
  
  <select id="selectUsers" resultType="User"> 
    SELECT <include refid="baseUserColumns"/> FROM users 
  </select>

逻辑分析:复用 SQL 片段能够提升代码的可维护性,避免了 SQL 语句的重复编写。

13. 处理枚举类型

通过 EnumTypeHandler 将枚举类型与数据库字段映射。

@EnumTypeHandler(EnumTypeHandler.class)
public enum UserStatus {    
   ACTIVE, INACTIVE;
}

逻辑分析:枚举类型处理器简化了枚举与数据库之间的映射,代码更加优雅且易于理解。

14. 多数据源支持

在项目中使用多数据源进行数据分离,确保高效的数据管理。

@Configuration
public class MyBatisConfig {    
   @Bean    
   public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { 
   SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();                            
   factoryBean.setDataSource(dataSource);        
   return factoryBean.getObject();    
   }
}

逻辑分析:多数据源支持让我们能够更好地管理不同的数据源,适用于微服务架构和复杂数据需求的场景。

15. 延迟加载

延迟加载可以提高性能,按需加载关联数据。

<settings> 
   <setting name="lazyLoadingEnabled" value="true"/>
</settings>

逻辑分析:延迟加载通过懒加载关联数据,避免不必要的查询,优化了性能。

总结

MyBatis 提供了多种灵活的功能,帮助开发者高效地进行数据库操作。通过使用动态 SQL、批量操作、resultMap、分页查询等技巧,开发者可以有效地简化 SQL 代码并提升查询性能。同时,MyBatis 支持自定义类型处理器、逻辑删除、分表策略等高级功能,适用于复杂的业务需求。掌握这些常见的 MyBatis 写法,不仅能够提升开发效率,还能确保系统在大数据量和复杂场景下的高效运行。