MyBatis-Plus从入门到精通
目录
简介
什么是MyBatis-Plus
MyBatis-Plus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。
核心特性
| 特性 | 说明 |
|---|---|
| 无侵入 | 只做增强不做改变,引入它不会对现有工程产生影响 |
| CRUD操作 | 内置通用Mapper、通用Service,可以无需编写SQL即可实现单表CRUD操作 |
| 条件构造器 | 使用Lambda表达式,可以方便地编写各类查询条件 |
| 主键策略 | 支持多达4种主键策略(内含分布式唯一ID生成器) |
| 分页插件 | 基于MyBatis物理分页,开发者无需关心具体操作 |
| 性能分析 | 可输出SQL语句以及其执行时间,建议开发测试时启用该功能 |
| 代码生成器 | 可快速生成Entity、Mapper、Mapper XML、Service、Controller等各个模块的代码 |
版本对比
| 版本 | 特性 | 兼容性 |
|---|---|---|
| 3.4.x | 基础功能完善,稳定版本 | MyBatis 3.4+ |
| 3.5.x | 新增Lambda查询,性能优化 | MyBatis 3.5+ |
| 3.6.x | 最新特性,支持JDK17+ | MyBatis 3.5+ |
源码分析
1. 核心架构图
2. BaseMapper源码分析
// BaseMapper接口定义
public interface BaseMapper<T> extends Mapper<T> {
// 插入一条记录
int insert(T entity);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 ID 修改
int updateById(@Param("et") T entity);
// 根据 ID 查询
T selectById(Serializable id);
// 查询所有记录
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Long selectCount(@Param("ew") Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
List<T> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
}
3. AbstractMethod源码分析
// AbstractMethod抽象类
public abstract class AbstractMethod implements Method {
protected Configuration configuration;
protected MethodSignature ms;
protected Class<?> mapperClass;
protected Class<?> modelClass;
@Override
public Object execute(Object[] args, SqlSession sqlSession) {
// 获取SQL语句
String sql = getSql();
// 获取参数
Object param = getParam(args);
// 执行SQL
return execute(sql, param, sqlSession);
}
// 抽象方法,由子类实现
protected abstract String getSql();
// 获取参数
protected Object getParam(Object[] args) {
return args[0];
}
// 执行SQL
protected Object execute(String sql, Object param, SqlSession sqlSession) {
// 具体实现逻辑
return null;
}
}
// SelectById方法实现
public class SelectById extends AbstractMethod {
@Override
protected String getSql() {
return String.format("SELECT %s FROM %s WHERE %s = #{id}",
getColumns(), getTableName(), getPrimaryKey());
}
@Override
protected Object execute(String sql, Object param, SqlSession sqlSession) {
return sqlSession.selectOne(sql, param);
}
}
4. 条件构造器源码分析
// AbstractWrapper抽象类
public abstract class AbstractWrapper<T, R, Children>
extends Wrapper<T> implements Compare<Children, R>, Nested<Children, Children>, Func<Children, R> {
// 查询字段
protected final List<String> sqlSelect = new ArrayList<>();
// 查询条件
protected final List<Object> expression = new ArrayList<>();
// 排序字段
protected final List<OrderBy> orderBy = new ArrayList<>();
// 分组字段
protected final List<String> groupBy = new ArrayList<>();
// 添加查询条件
protected Children addCondition(String column, Object val, String type) {
expression.add(new Condition(column, val, type));
return typedThis();
}
// 构建SQL
public String getSqlSegment() {
StringBuilder sql = new StringBuilder();
// 添加WHERE条件
if (!expression.isEmpty()) {
sql.append(" WHERE ");
for (int i = 0; i < expression.size(); i++) {
if (i > 0) sql.append(" AND ");
sql.append(expression.get(i).getSqlSegment());
}
}
// 添加GROUP BY
if (!groupBy.isEmpty()) {
sql.append(" GROUP BY ").append(String.join(", ", groupBy));
}
// 添加ORDER BY
if (!orderBy.isEmpty()) {
sql.append(" ORDER BY ");
for (int i = 0; i < orderBy.size(); i++) {
if (i > 0) sql.append(", ");
sql.append(orderBy.get(i).getSqlSegment());
}
}
return sql.toString();
}
}
// QueryWrapper实现类
public class QueryWrapper<T> extends AbstractWrapper<T, String, QueryWrapper<T>> {
// 等值查询
public QueryWrapper<T> eq(String column, Object val) {
return addCondition(column, val, "=");
}
// 模糊查询
public QueryWrapper<T> like(String column, Object val) {
return addCondition(column, val, "LIKE");
}
// 范围查询
public QueryWrapper<T> between(String column, Object val1, Object val2) {
return addCondition(column, Arrays.asList(val1, val2), "BETWEEN");
}
}
5. 分页插件源码分析
// PaginationInnerInterceptor分页插件
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class PaginationInnerInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
// 获取分页参数
IPage<?> page = getPage(metaObject);
if (page == null) {
return invocation.proceed();
}
// 获取原始SQL
String originalSql = getOriginalSql(metaObject);
// 构建分页SQL
String pageSql = buildPageSql(originalSql, page);
// 设置分页SQL
metaObject.setValue("delegate.boundSql.sql", pageSql);
return invocation.proceed();
}
// 构建分页SQL
protected String buildPageSql(String originalSql, IPage<?> page) {
if (page.getCurrent() <= 1) {
// 第一页
return originalSql + " LIMIT " + page.getSize();
} else {
// 其他页
long offset = (page.getCurrent() - 1) * page.getSize();
return originalSql + " LIMIT " + offset + "," + page.getSize();
}
}
}
SpringBoot集成
1. 依赖配置
<!-- Maven依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
<!-- 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3</version>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
2. 配置文件
# application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 123456
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
mapper-locations: classpath*:/mapper/**/*.xml
type-aliases-package: com.example.entity
3. 配置类
@Configuration
@MapperScan("com.example.mapper")
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
return new OptimisticLockerInnerInterceptor();
}
/**
* 动态表名插件
*/
@Bean
public DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {
DynamicTableNameInnerInterceptor interceptor = new DynamicTableNameInnerInterceptor();
interceptor.setTableNameHandler((sql, tableName) -> {
// 动态表名逻辑
return tableName + "_" + LocalDate.now().getYear();
});
return interceptor;
}
}
4. 实体类
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("user_name")
private String userName;
@TableField("email")
private String email;
@TableField("age")
private Integer age;
@TableField("create_time")
private LocalDateTime createTime;
@TableField("update_time")
private LocalDateTime updateTime;
@TableLogic
@TableField("deleted")
private Integer deleted;
@Version
@TableField("version")
private Integer version;
}
5. Mapper接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 自定义查询方法
@Select("SELECT * FROM user WHERE age > #{age}")
List<User> selectUsersByAge(@Param("age") Integer age);
// 自定义更新方法
@Update("UPDATE user SET email = #{email} WHERE id = #{id}")
int updateEmailById(@Param("id") Long id, @Param("email") String email);
// 复杂查询
List<User> selectUsersByCondition(@Param("userName") String userName,
@Param("minAge") Integer minAge,
@Param("maxAge") Integer maxAge);
}
6. Service接口和实现
// Service接口
public interface UserService extends IService<User> {
// 自定义业务方法
List<User> getUsersByAgeRange(Integer minAge, Integer maxAge);
// 批量操作
boolean batchUpdateUsers(List<User> users);
// 分页查询
IPage<User> getUserPage(IPage<User> page, String userName);
}
// Service实现
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public List<User> getUsersByAgeRange(Integer minAge, Integer maxAge) {
return this.list(new QueryWrapper<User>()
.between("age", minAge, maxAge)
.orderByDesc("create_time"));
}
@Override
public boolean batchUpdateUsers(List<User> users) {
return this.updateBatchById(users);
}
@Override
public IPage<User> getUserPage(IPage<User> page, String userName) {
return this.page(page, new QueryWrapper<User>()
.like(StringUtils.isNotBlank(userName), "user_name", userName)
.orderByDesc("create_time"));
}
}
7. Controller
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 分页查询用户
*/
@GetMapping("/page")
public Result<IPage<User>> getUserPage(
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String userName) {
IPage<User> page = new Page<>(current, size);
IPage<User> result = userService.getUserPage(page, userName);
return Result.success(result);
}
/**
* 新增用户
*/
@PostMapping
public Result<Boolean> addUser(@RequestBody User user) {
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
boolean result = userService.save(user);
return Result.success(result);
}
/**
* 更新用户
*/
@PutMapping
public Result<Boolean> updateUser(@RequestBody User user) {
user.setUpdateTime(LocalDateTime.now());
boolean result = userService.updateById(user);
return Result.success(result);
}
/**
* 删除用户
*/
@DeleteMapping("/{id}")
public Result<Boolean> deleteUser(@PathVariable Long id) {
boolean result = userService.removeById(id);
return Result.success(result);
}
}
逆向工程配置
1. 代码生成器配置
@Configuration
public class CodeGeneratorConfig {
@Autowired
private DataSource dataSource;
/**
* 代码生成器
*/
public void generateCode() {
// 数据源配置
DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig
.Builder("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8", "root", "123456");
// 全局配置
GlobalConfig.Builder globalConfigBuilder = new GlobalConfig.Builder()
.author("作者名")
.dateType(DateType.TIME_PACK)
.commentDate("yyyy-MM-dd")
.outputDir(System.getProperty("user.dir") + "/src/main/java")
.disableOpenDir();
// 包配置
PackageConfig.Builder packageConfigBuilder = new PackageConfig.Builder()
.parent("com.example")
.entity("entity")
.mapper("mapper")
.xml("mapper.xml")
.service("service")
.serviceImpl("service.impl")
.controller("controller");
// 策略配置
StrategyConfig.Builder strategyConfigBuilder = new StrategyConfig.Builder()
.addInclude("user", "order", "product") // 表名
.addTablePrefix("t_") // 表前缀
.entityBuilder()
.enableLombok()
.enableTableFieldAnnotation()
.logicDeleteColumnName("deleted")
.versionColumnName("version")
.naming(NamingStrategy.underline_to_camel)
.mapperBuilder()
.enableMapperAnnotation()
.enableBaseResultMap()
.enableBaseColumnList()
.serviceBuilder()
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.controllerBuilder()
.enableRestStyle()
.enableHyphenStyle();
// 模板配置
TemplateConfig.Builder templateConfigBuilder = new TemplateConfig.Builder()
.entity("/templates/entity.java")
.mapper("/templates/mapper.java")
.xml("/templates/mapper.xml")
.service("/templates/service.java")
.serviceImpl("/templates/serviceImpl.java")
.controller("/templates/controller.java");
// 执行生成
FastAutoGenerator.create(dataSourceConfigBuilder)
.globalConfig(globalConfigBuilder.build())
.packageConfig(packageConfigBuilder.build())
.strategyConfig(strategyConfigBuilder.build())
.templateConfig(templateConfigBuilder.build())
.execute();
}
}
2. 自定义模板
// 自定义Entity模板
public class CustomEntityTemplate extends AbstractTemplate {
@Override
public String getTemplatePath() {
return "/templates/entity.java.ftl";
}
@Override
public String getFileName(String tableName) {
return String.format("%s.java", tableName);
}
}
// 自定义Mapper模板
public class CustomMapperTemplate extends AbstractTemplate {
@Override
public String getTemplatePath() {
return "/templates/mapper.java.ftl";
}
@Override
public String getFileName(String tableName) {
return String.format("%sMapper.java", tableName);
}
}
3. 生成器使用示例
@Component
public class CodeGenerator {
public void generate() {
// 数据库连接配置
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8";
String username = "root";
String password = "123456";
// 代码生成器
FastAutoGenerator.create(url, username, password)
// 全局配置
.globalConfig(builder -> {
builder.author("作者名") // 设置作者
.enableSwagger() // 开启swagger模式
.fileOverride() // 覆盖已生成文件
.outputDir("D://"); // 指定输出目录
})
// 包配置
.packageConfig(builder -> {
builder.parent("com.example") // 设置父包名
.moduleName("system") // 设置模块名
.entity("entity") // 设置entity包名
.mapper("mapper") // 设置mapper包名
.xml("mapper.xml") // 设置mapper xml包名
.service("service") // 设置service包名
.serviceImpl("service.impl") // 设置service impl包名
.controller("controller"); // 设置controller包名
})
// 策略配置
.strategyConfig(builder -> {
builder.addInclude("user") // 设置需要生成的表名
.addTablePrefix("t_") // 设置过滤表前缀
// Entity策略配置
.entityBuilder()
.enableLombok() // 开启lombok
.enableTableFieldAnnotation() // 开启生成实体时生成字段注解
.logicDeleteColumnName("deleted") // 逻辑删除字段名
.versionColumnName("version") // 乐观锁字段名
.naming(NamingStrategy.underline_to_camel) // 命名策略
// Mapper策略配置
.mapperBuilder()
.enableMapperAnnotation() // 开启@Mapper注解
.enableBaseResultMap() // 启用BaseResultMap生成
.enableBaseColumnList() // 启用BaseColumnList生成
// Service策略配置
.serviceBuilder()
.formatServiceFileName("%sService") // 格式化service接口文件名称
.formatServiceImplFileName("%sServiceImpl") // 格式化service实现类文件名称
// Controller策略配置
.controllerBuilder()
.enableRestStyle() // 开启生成@RestController
.enableHyphenStyle(); // 开启驼峰转连字符
})
// 模板配置
.templateConfig(builder -> {
builder.entity("/templates/entity.java")
.mapper("/templates/mapper.java")
.xml("/templates/mapper.xml")
.service("/templates/service.java")
.serviceImpl("/templates/serviceImpl.java")
.controller("/templates/controller.java");
})
// 执行
.execute();
}
}
面试高频点
1. 基础概念
Q1: MyBatis-Plus和MyBatis的区别?
A:
- MyBatis: 需要手写SQL,提供基础的ORM功能
- MyBatis-Plus: 在MyBatis基础上增强,提供通用CRUD操作,减少重复代码
- 关系: MyBatis-Plus是MyBatis的增强工具,完全兼容MyBatis
Q2: MyBatis-Plus的核心特性有哪些?
A:
- 无侵入: 只做增强不做改变
- CRUD操作: 内置通用Mapper、通用Service
- 条件构造器: 使用Lambda表达式编写查询条件
- 主键策略: 支持多种主键生成策略
- 分页插件: 基于MyBatis物理分页
- 代码生成器: 快速生成各模块代码
Q3: MyBatis-Plus支持哪些主键策略?
A:
public enum IdType {
AUTO, // 数据库自增
NONE, // 无状态
INPUT, // 用户输入
ASSIGN_ID, // 分配ID (默认雪花算法)
ASSIGN_UUID, // 分配UUID
/** @deprecated */
@Deprecated
ID_WORKER, // 全局唯一ID (idWorker)
/** @deprecated */
@Deprecated
ID_WORKER_STR, // 字符串全局唯一ID (idWorker 的字符串表示)
/** @deprecated */
@Deprecated
UUID // 全局唯一ID (UUID)
}
2. 条件构造器
Q4: QueryWrapper和LambdaQueryWrapper的区别?
A:
- QueryWrapper: 使用字符串列名,类型不安全,但灵活性高
- LambdaQueryWrapper: 使用Lambda表达式,类型安全,编译时检查,推荐使用
// QueryWrapper示例
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_name", "张三")
.ge("age", 18)
.like("email", "@gmail.com");
// LambdaQueryWrapper示例
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(User::getUserName, "张三")
.ge(User::getAge, 18)
.like(User::getEmail, "@gmail.com");
Q5: 如何实现动态查询条件?
A:
public List<User> getUsers(String userName, Integer minAge, Integer maxAge) {
return this.list(new LambdaQueryWrapper<User>()
.like(StringUtils.isNotBlank(userName), User::getUserName, userName)
.ge(minAge != null, User::getAge, minAge)
.le(maxAge != null, User::getAge, maxAge)
.orderByDesc(User::getCreateTime));
}
3. 分页插件
Q6: MyBatis-Plus分页插件的原理是什么?
A:
- 原理: 基于MyBatis的Interceptor拦截器,在SQL执行前动态修改SQL语句
- 流程: 拦截StatementHandler.prepare方法 → 获取分页参数 → 构建分页SQL → 替换原始SQL
- 特点: 物理分页,性能好,支持多种数据库
Q7: 如何配置分页插件?
A:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
4. 性能优化
Q8: MyBatis-Plus有哪些性能优化点?
A:
- 批量操作: 使用saveBatch、updateBatchById等方法
- 分页查询: 合理设置分页大小,避免深度分页
- 条件构造: 使用Lambda表达式,避免字符串拼接
- 缓存策略: 合理使用MyBatis缓存
- SQL优化: 避免N+1查询问题
Q9: 如何处理N+1查询问题?
A:
// 错误示例:N+1查询
List<User> users = userService.list();
for (User user : users) {
List<Order> orders = orderService.list(new LambdaQueryWrapper<Order>()
.eq(Order::getUserId, user.getId()));
user.setOrders(orders);
}
// 正确示例:批量查询
List<User> users = userService.list();
List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
List<Order> allOrders = orderService.list(new LambdaQueryWrapper<Order>()
.in(Order::getUserId, userIds));
// 按用户ID分组
Map<Long, List<Order>> orderMap = allOrders.stream()
.collect(Collectors.groupingBy(Order::getUserId));
// 设置用户订单
users.forEach(user -> user.setOrders(orderMap.get(user.getId())));
5. 高级特性
Q10: 如何实现逻辑删除?
A:
// 实体类配置
@TableLogic
@TableField("deleted")
private Integer deleted;
// 配置文件中设置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
// 使用
userService.removeById(1L); // 实际执行UPDATE语句,设置deleted=1
userService.list(); // 查询时自动添加WHERE deleted=0条件
Q11: 如何实现乐观锁?
A:
// 实体类配置
@Version
@TableField("version")
private Integer version;
// 配置乐观锁插件
@Bean
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
return new OptimisticLockerInnerInterceptor();
}
// 使用
User user = userService.getById(1L);
user.setUserName("新用户名");
userService.updateById(user); // 自动检查version字段,防止并发更新
最佳实践
1. 实体类设计
@Data
@TableName("user")
@EqualsAndHashCode(callSuper = false)
public class User extends BaseEntity {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
@TableField(value = "user_name", fill = FieldFill.INSERT)
private String userName;
@TableField("email")
private String email;
@TableField("age")
private Integer age;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
@TableField("deleted")
private Integer deleted;
@Version
@TableField("version")
private Integer version;
// 不映射到数据库的字段
@TableField(exist = false)
private List<Order> orders;
}
2. 字段自动填充
@Component
public class MetaObjectHandler implements com.baomidou.mybatisplus.core.handlers.MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "deleted", Integer.class, 0);
this.strictInsertFill(metaObject, "version", Integer.class, 1);
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
3. 异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MybatisPlusException.class)
public Result<String> handleMybatisPlusException(MybatisPlusException e) {
log.error("MyBatis-Plus异常: {}", e.getMessage(), e);
return Result.error("数据库操作异常: " + e.getMessage());
}
@ExceptionHandler(DataIntegrityViolationException.class)
public Result<String> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
log.error("数据完整性异常: {}", e.getMessage(), e);
return Result.error("数据完整性约束违反");
}
}
4. 性能监控
@Component
public class SqlPerformanceInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long startTime = System.currentTimeMillis();
try {
return invocation.proceed();
} finally {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
if (duration > 1000) { // 超过1秒的SQL记录警告
log.warn("SQL执行时间过长: {}ms", duration);
}
log.info("SQL执行时间: {}ms", duration);
}
}
}
总结
1. 学习路径图
2. 核心优势
| 优势 | 说明 |
|---|---|
| 开发效率 | 减少重复代码,提高开发速度 |
| 类型安全 | Lambda表达式,编译时检查 |
| 性能优化 | 内置分页插件,批量操作 |
| 扩展性强 | 插件机制,支持自定义扩展 |
| 学习成本低 | 基于MyBatis,学习曲线平缓 |
3. 适用场景
| 场景 | 说明 |
|---|---|
| 快速开发 | 新项目快速搭建,减少重复工作 |
| CRUD操作 | 单表操作频繁的业务场景 |
| 分页查询 | 需要分页展示的数据列表 |
| 代码生成 | 标准化的增删改查功能 |
4. 注意事项
| 注意点 | 说明 |
|---|---|
| 性能考虑 | 避免N+1查询,合理使用批量操作 |
| 事务管理 | 复杂业务逻辑需要手动管理事务 |
| SQL优化 | 复杂查询建议手写SQL |
| 版本兼容 | 注意MyBatis版本兼容性 |
5. 学习建议
通过系统学习MyBatis-Plus,可以:
- 提高开发效率 - 减少重复代码编写
- 增强代码质量 - 类型安全,减少错误
- 掌握ORM框架 - 深入理解MyBatis原理
- 提升技术能力 - 为高级开发打下基础
实践建议: 在实际项目中多应用MyBatis-Plus,通过实践加深理解,逐步掌握其高级特性和最佳实践。记住:工具是手段,理解原理才是根本。

5551

被折叠的 条评论
为什么被折叠?



