简介:本文详细探讨MyBatis-Plus中Wrapper自定义SQL的实现方法,结合自定义模板生成技术,提供从基础配置到高级应用的完整解决方案。
MyBatis-Plus作为MyBatis的增强工具,其核心Wrapper机制通过构建条件链式调用,实现了SQL语句的动态生成。LambdaQueryWrapper和QueryWrapper作为主要实现类,提供了where()、eq()、like()等链式方法,底层通过AbstractLambdaWrapper的逻辑处理器将方法调用转换为SQL片段。
当执行new LambdaQueryWrapper<User>().eq(User::getName, "test")时,系统会:
虽然Wrapper提供了便捷的CRUD操作,但在处理复杂SQL时存在明显不足:
在resources/mapper目录下创建UserMapper.xml:
<select id="selectByCustomCondition" resultType="User">SELECT * FROM userWHERE name LIKE CONCAT('%', #{name}, '%')<if test="minAge != null">AND age >= #{minAge}</if></select>
对应Mapper接口:
public interface UserMapper extends BaseMapper<User> {List<User> selectByCustomCondition(@Param("name") String name,@Param("minAge") Integer minAge);}
@Select({"<script>","SELECT * FROM user","WHERE name LIKE CONCAT('%', #{name}, '%')","<if test='minAge != null'>"," AND age >= #{minAge}","</if>","</script>"})List<User> selectByCustomCondition(@Param("name") String name,@Param("minAge") Integer minAge);
通过@Select注解结合Wrapper参数:
@Select("SELECT * FROM user ${ew.customSqlSegment}")List<User> selectByWrapper(@Param(Constants.WRAPPER) Wrapper wrapper);
使用时:
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.like(User::getName, "test").ge(User::getAge, 18);userMapper.selectByWrapper(wrapper);
在application.yml中配置:
mybatis-plus:global-config:db-config:id-type: autoconfiguration:default-script-language: velocitygenerator:template-path: /templates/
entity.java.vm模板核心部分:
package ${package.Entity};import java.io.Serializable;#foreach($import in ${table.imports})import ${import};#endpublic class ${entity} implements Serializable {#foreach($field in ${table.fields})private ${field.propertyType} ${field.propertyName};#end#foreach($field in ${table.fields})public ${field.propertyType} get${field.capitalName}() {return ${field.propertyName};}public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {this.${field.propertyName} = ${field.propertyName};}#end}
通过Interceptor实现动态表名:
public class DynamicTableNameInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement) args[0];Object parameter = args[1];if (parameter instanceof Map) {Map paramMap = (Map) parameter;if (paramMap.containsKey("tableName")) {// 修改SQL中的表名BoundSql boundSql = ms.getBoundSql(parameter);String sql = boundSql.getSql();sql = sql.replace("user", (String) paramMap.get("tableName"));// 重新设置SQL// ...}}return invocation.proceed();}}
配置多数据源:
@Configurationpublic 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();}@Beanpublic DataSource dynamicDataSource() {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", masterDataSource());targetDataSources.put("slave", slaveDataSource());DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(masterDataSource());return dynamicDataSource;}}
使用PageHelper或MyBatis-Plus自带分页:
// MyBatis-Plus分页Page<User> page = new Page<>(1, 10);IPage<User> userPage = userMapper.selectPage(page, wrapper);
确保Service方法添加@Transactional注解:
@Service@Transactional(rollbackFor = Exception.class)public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic boolean updateUser(User user) {return userMapper.updateById(user) > 0;}}
配置二级缓存:
mybatis-plus:configuration:cache-enabled: true
MyBatis-Plus的Wrapper机制与自定义SQL结合使用,既保留了链式调用的便捷性,又弥补了复杂查询的不足。通过自定义模板生成,可以大幅提升开发效率,保证代码的一致性。未来发展方向包括:
建议开发者根据项目实际需求,合理选择Wrapper与自定义SQL的使用比例,建立完善的代码生成规范,持续提升开发效率与代码质量。