MyBatis写法汇总

发布于:2024-12-19 ⋅ 阅读:(15) ⋅ 点赞:(0)

Mybatis写法汇总

1. 批量操作

1.1 批量插入

<insert id="batchInsert" parameterType="java.util.List">
    INSERT INTO user (username, password, create_time) VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.username}, #{item.password}, #{item.createTime})
    </foreach>
</insert>

1.2 批量更新

<update id="batchUpdate" parameterType="java.util.List">
    <foreach collection="list" item="item" separator=";">
        UPDATE user
        SET username = #{item.username}, password= #{item.password}
        WHERE id = #{item.id}
    </foreach>
</update>

1.3 批量删除

<delete id="batchDelete" parameterType="java.util.List">
    DELETE FROM user WHERE id IN
    <foreach collection="list" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</delete>

通过使用<foreach> 标签,我们可以将多个操作合并为一条SQL语句,大大减少了数据库交互次数,提高了操作效率。

2. 动态SQL

动态SQL是MyBatis的强大特性之一,允许我们根据不同的条件动态构建SQL语句。<if>标签是实现动态SQL的核心。

2.1 动态查询

<select id="findUsers" resultType="User">
    SELECT * FROM user
    WHERE 1=1
    <if test="username != null and username != ''">
        AND username LIKE CONCAT('%', #{username}, '%')
    </if>
    <if test="email != null and email != ''">
        AND email = #{email}
    </if>
    <if test="status != null">
        AND status = #{status}
    </if>
</select>

3. 多条件分支查询

对于更复杂的查询逻辑,我们可以使用<choose>、<when>和<otherwise>标签来实现多条件分支查询。

<select id="findUsersByCondition" resultType="User">
    SELECT * FROM user
    WHERE 1=1
    <choose>
        <when test="searchType == 'username'">
            AND username LIKE CONCAT('%', #{keyword}, '%')
        </when>
        <when test="searchType == 'email'">
            AND email LIKE CONCAT('%', #{keyword}, '%')
        </when>
        <otherwise>
            AND (username LIKE CONCAT('%', #{keyword}, '%') OR email LIKE CONCAT('%', #{keyword}, '%'))
        </otherwise>
    </choose>
</select>

这个例子展示了如何根据不同的搜索类型选择不同的查询条件,如果没有指定搜索类型,则默认搜索用户名和邮箱。

4. SQL语句优化

使用 <trim> 标签可以帮助我们优化生成的SQL语句,避免出现多余的AND或OR关键字。

<select id="findUsers" resultType="User">
    SELECT * FROM user
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
        <if test="username != null and username != ''">
            AND username LIKE CONCAT('%', #{username}, '%')
        </if>
        <if test="email != null and email != ''">
            AND email = #{email}
        </if>
        <if test="status != null">
            AND status = #{status}
        </if>
    </trim>
</select>

在这个例子中,<trim>标签会自动去除第一个多余的AND或OR,并在有查询条件时添加WHERE关键字。

5. 自动生成主键

在插入操作中,我们经常需要获取数据库自动生成的主键。MyBatis提供了<selectKey>标签来实现这一功能。

<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
        SELECT 2531020
    </selectKey>
    INSERT INTO user (username, email, create_time)
    VALUES (#{username}, #{email}, #{createTime})
</insert>

在这个例子中,插入操作完成后,会自动执行SELECT 2531020获取新插入记录的ID,并将其赋值给传入的User对象的id属性。

6. 注解方式使用MyBatis

除了XML配置,MyBatis还支持使用注解来定义SQL操作,这种方式可以使代码更加简洁。

public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserById(Long id);

    @Insert("INSERT INTO user (username, email, create_time) VALUES (#{username}, #{email}, #{createTime})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insertUser(User user);

    @Update("UPDATE user SET username = #{username}, email = #{email} WHERE id = #{id}")
    int updateUser(User user);

    @Delete("DELETE FROM user WHERE id = #{id}")
    int deleteUser(Long id);
}

这种方式适合简单的CRUD操作,但对于复杂的SQL语句,仍然建议使用XML配置。

7. 高级映射

MyBatis提供了强大的对象关系映射功能,可以处理复杂的表关系。

一对多映射示例:

<resultMap id="userWithOrdersMap" type="User">
    <id property="id" column="user_id"/>
    <result property="username" column="username"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="orderNumber" column="order_number"/>
        <result property="createTime" column="order_create_time"/>
    </collection>
</resultMap>

<select id="getUserWithOrders" resultMap="userWithOrdersMap">
    SELECT u.id as user_id, u.username, o.id as order_id, o.order_number, o.create_time as order_create_time
    FROM user u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = #{userId}
</select>

8. MyBatis-Plus集成

MyBatis-Plus是MyBatis的增强工具,它提供了许多便捷的CRUD操作和强大的条件构造器。

MyBatis-Plus使用示例:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    public List<User> findUsersByCondition(String username, String email) {
        return this.list(new QueryWrapper<User>()
                .like(StringUtils.isNotBlank(username), "username", username)
                .eq(StringUtils.isNotBlank(email), "email", email));
    }
}

在这个例子中,我们使用MyBatis-Plus提供的条件构造器来动态构建查询条件,无需编写XML。

9. 事务管理

在Spring环境中,我们可以使用@Transactional注解来管理事务,确保数据的一致性。
事务管理示例:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void createUserWithOrders(User user, List<Order> orders) {
        userMapper.insert(user);
        for (Order order : orders) {
            order.setUserId(user.getId());
            orderMapper.insert(order);
        }
    }
}

在这个例子中,创建用户和订单的操作被包装在一个事务中,如果任何一步失败,整个操作都会回滚。

10. 缓存机制

MyBatis提供了一级缓存和二级缓存,可以有效提高查询性能。

二级缓存配置示例:

<cache
  eviction="LRU"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个配置启用了LRU淘汰策略的二级缓存,缓存容量为512个对象,每60秒刷新一次。

11. 插件使用

MyBatis插件可以拦截核心方法的调用,实现如分页、性能分析等功能。
分页插件示例 (使用PageHelper):

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public PageInfo<User> getUserList(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<User> users = userMapper.selectAll();
        return new PageInfo<>(users);
    }
}

这个例子展示了如何使用PageHelper插件实现简单的分页功能。

12. 多数据源配置

在某些场景下,我们需要在同一个应用中操作多个数据库。MyBatis支持配置多个数据源来实现这一需求。

多数据源配置示例:

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        return factoryBean.getObject();
    }
}

这个配置类定义了两个数据源和对应的SqlSessionFactory,可以在不同的Mapper中使用不同的数据源。

13. 读写分离

读写分离是提高数据库性能的常用策略。MyBatis可以通过配置多数据源来实现简单的读写分离。

读写分离配置示例:

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public DataSource routingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                                        @Qualifier("slaveDataSource") DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
        targetDataSources.put(DataSourceType.SLAVE, slaveDataSource);

        AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {
            @Override
            protected Object determineCurrentLookupKey() {
                return DataSourceContextHolder.getDataSourceType();
            }
        };
        routingDataSource.setTargetDataSources(targetDataSources);
        routingDataSource.setDefaultTargetDataSource(masterDataSource);

        return routingDataSource;
    }
}

这个例子定义了一个动态数据源,可以根据上下文选择主库或从库。你需要实现一个DataSourceContextHolder来管理当前线程的数据源类型。

14. SQL分析和优化

MyBatis提供了SQL执行分析功能,可以帮助我们找出性能瓶颈。
SQL分析配置示例:

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
        <property name="offsetAsPageNum" value="true"/>
        <!-- 设置为true时,使用RowBounds分页会进行count查询 -->
        <property name="rowBoundsWithCount" value="true"/>
    </plugin>
    <plugin interceptor="org.apache.ibatis.plugin.Interceptor">
        <property name="properties">
            sqlCollector=com.example.SqlCollector
        </property>
    </plugin>
</plugins>

在这个配置中,我们不仅加入了分页插件,还加入了一个自定义的SQL收集器,可以用于分析SQL执行情况。

总结

我们详细介绍了14种MyBatis的高级用法和技巧,涵盖了从基本的CRUD操作优化到复杂的多数据源配置和读写分离等高级主题。这些技巧可以帮助开发者更高效地使用MyBatis,构建出性能更好、可维护性更强的应用系统。