MyBatis 生态深度解析:MyBatis、MyBatis Plus 与 tk-mybatis 的技术选型指南
一、引言:ORM 框架的演进与选择困境
在 Java 企业级应用开发中,数据访问层的设计一直是个关键挑战。从早期的 JDBC 直接操作,到 Hibernate 的全自动 ORM,再到 MyBatis 的半自动 ORM,开发者在灵活性与开发效率之间不断寻找平衡点。
如今,MyBatis 作为国内最主流的持久层框架,已衍生出多个增强版本,其中 MyBatis Plus 和 tk-mybatis 最为瞩目。面对这"一源两支"的技术生态,许多架构师和开发者陷入选择困境:
- 小型项目该用原生 MyBatis 还是增强框架?
- MyBatis Plus 和 tk-mybatis 哪个更适合高并发场景?
- 旧项目升级时该如何选择迁移路径?
- 三者在性能、学习曲线和生态支持上有何差异?
本文将深入剖析这三个框架的核心原理、技术特性与应用场景,通过大量实战代码和性能对比,为你提供清晰的技术选型指南。
二、核心框架解剖:设计哲学与架构差异
2.1 MyBatis:基础与自由的平衡
核心定位:MyBatis 不是一个全自动 ORM 框架,而是一个 SQL 映射框架。它将 SQL 语句与 Java 对象解耦,同时保留了手写 SQL 的灵活性。
架构设计:
graph TD
A[Java Application] -->|调用| B[Mapper Interface]
B -->|代理实现| C[MyBatis Core]
C -->|解析| D[XML/Annotation SQL]
C -->|执行| E[JDBC]
E -->|连接| F[Database]
核心组件:
- SqlSessionFactory:线程安全的工厂,用于创建 SqlSession
- SqlSession:非线程安全的操作单元,包含 CRUD 方法
- MapperProxy:JDK 动态代理实现接口方法
- Executor:SQL 执行器,支持简单、重用、批处理等模式
- TypeHandler:Java 类型与 JDBC 类型的转换器
设计哲学:
- 显式优于隐式:SQL 语句显式定义,而非自动生成
- 最小侵入性:不强制 POJO 继承特定类或实现特定接口
- 高度可定制:通过插件机制(Interceptor)扩展功能
典型代码:
<!-- UserMapper.xml -->
<select id="selectUserById" resultType="com.example.User">
SELECT id, name, email, create_time
FROM users
WHERE id = #{id}
AND is_deleted = 0
</select>
// Mapper接口
public interface UserMapper {
User selectUserById(Long id);
@Select("SELECT * FROM users WHERE name LIKE CONCAT('%',#{name},'%')")
List<User> searchUsersByName(@Param("name") String name);
}
2.2 MyBatis Plus:国产增强的全栈解决方案
核心定位:MyBatis Plus (MP) 是国内开源的 MyBatis 增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
架构增强:
graph TD
A[MyBatis Core] --> B[MyBatis Plus Core]
B --> C[通用Mapper]
B --> D[通用Service]
B --> E[条件构造器]
B --> F[插件体系]
F --> G[分页插件]
F --> H[性能分析插件]
F --> I[乐观锁插件]
F --> J[防止全表更新插件]
核心创新:
- 无侵入式设计:通过 MyBatis 的插件机制实现增强,不修改 MyBatis 核心代码
- 通用 CRUD:BaseMapper 接口提供 18+ 个通用方法,无需编写简单 SQL
- 条件构造器:QueryWrapper/UpdateWrapper/LambdaQueryWrapper 提供链式 API 构建复杂条件
- ActiveRecord 模式:实体类可直接操作数据库,简化 Service 层
- 多租户支持:内置数据隔离方案
- 代码生成器:一键生成 Entity、Mapper、Service、Controller 等全套代码
技术亮点:
- Lambda 表达式支持:避免硬编码字段名,提高代码可重构性
- 自动填充:@TableField 注解实现创建时间、更新时间等字段自动填充
- 乐观锁:@Version 注解实现版本号控制
- 逻辑删除:@TableLogic 注解实现软删除,查询自动过滤
典型代码:
// 实体类
@Data
@TableName("users")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableLogic
private Integer isDeleted;
}
// Mapper接口 - 无需编写SQL
public interface UserMapper extends BaseMapper<User> {}
// 服务层调用
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 通用查询
public List<User> getUsersByAge(Integer minAge, Integer maxAge) {
return userMapper.selectList(
new LambdaQueryWrapper<User>()
.ge(User::getAge, minAge)
.le(User::getAge, maxAge)
.orderByDesc(User::getCreateTime)
);
}
// 分页查询
public Page<User> pageUsers(int pageNum, int pageSize) {
Page<User> page = new Page<>(pageNum, pageSize);
return userMapper.selectPage(page,
new LambdaQueryWrapper<User>().orderByDesc(User::getCreateTime));
}
}
2.3 tk-mybatis:轻量级的国际范
核心定位:tk-mybatis (原 Mapper) 是一个 MyBatis 通用 Mapper 工具,专注于简化单表 CRUD 操作,保持轻量级设计。
架构特点:
graph LR
A[MyBatis Core] --> B[tk-mybatis Core]
B --> C[Mapper<T> Interface]
B --> D[Example 类]
B --> E[MySqlMapper etc.]
B --> F[代码生成器]
核心创新:
- 极简侵入:只需继承
Mapper<T>接口,不强制实体类注解 - Example 模式:通过 Example 类构建动态查询条件
- 多数据库支持:针对 MySQL、Oracle 等提供专用扩展
- 轻量级设计:核心 jar 仅 200KB 左右,依赖少
- 国际化支持:文档完善,对非中文环境友好
设计理念:
- 约定优于配置:通过命名约定简化配置
- 保持原生 MyBatis 体验:不改变 MyBatis 使用习惯
- 单一职责:专注于单表操作,复杂查询仍用原生 MyBatis
典型代码:
// 实体类(无注解示例)
public class User {
private Long id;
private String name;
private String email;
private Date createTime;
// getters/setters
}
// Mapper接口
public interface UserMapper extends Mapper<User> {
// 可以继续定义自己的方法
@Select("SELECT * FROM users WHERE name LIKE CONCAT('%',#{name},'%')")
List<User> searchByName(String name);
}
// 服务层调用
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 通用查询
public List<User> getUsersByAge(Integer minAge, Integer maxAge) {
Example example = new Example(User.class);
example.createCriteria()
.andGreaterThan("age", minAge)
.andLessThanOrEqualTo("age", maxAge);
example.orderBy("createTime").desc();
return userMapper.selectByExample(example);
}
// 分页需要配合PageHelper
public PageInfo<User> pageUsers(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectAll();
return new PageInfo<>(users);
}
}
三、深度对比:功能、性能与生态
3.1 核心功能对比表
| 特性 | MyBatis | MyBatis Plus | tk-mybatis |
|---|---|---|---|
| 单表 CRUD | 需手写 SQL | 内置通用 Mapper,18+ 方法 | 内置 Mapper,20+ 方法 |
| 条件构造器 | 无,需拼接 SQL | QueryWrapper/Lambda 链式 API | Example 类 |
| 分页支持 | 需自定义或插件 | 内置分页插件,支持多种数据库 | 需 PageHelper 插件 |
| 逻辑删除 | 需手动处理 | @TableLogic 注解支持 | 需自定义 |
| 自动填充 | 需拦截器实现 | @TableField(fill=) 支持 | 需自定义 |
| 乐观锁 | 需手动实现 | @Version 注解支持 | 需自定义 |
| Lambda 表达式 | 不支持 | 完整支持 | 部分支持(3.5+) |
| 多租户 | 需自定义 | 内置方案 | 需自定义 |
| 代码生成器 | 第三方工具 | 内置强大生成器 | 内置生成器 |
| AR 模式 | 不支持 | 支持(实体直接操作 DB) | 不支持 |
| JPA 风格 | 不支持 | 部分支持(条件构造器) | 支持(Example 模式) |
| 学习曲线 | 中 | 陡峭(功能多) | 平缓 |
| 核心 jar 大小 | 1.2MB | 1.8MB | 0.2MB |
| 文档语言 | 英文 | 中文 | 中/英文 |
3.2 性能基准测试(50,000 次简单查询)
测试环境:
- Intel i7-12700H, 32GB RAM
- JDK 17, Spring Boot 3.0
- MySQL 8.0, 100 万数据量
- JMH 基准测试框架
测试场景:
- 单记录查询 (ID=1)
- 条件查询 (status=1, age>20)
- 分页查询 (page=5, size=20)
- 批量插入 (1000 条)
| 框架 | 单记录查询(ops/s) | 条件查询(ops/s) | 分页查询(ms) | 批量插入(ms) |
|---|---|---|---|---|
| MyBatis | 12,850 ± 142 | 8,720 ± 95 | 42.3 ± 1.2 | 1250 ± 24 |
| MyBatis Plus | 11,980 ± 156 (-6.8%) | 7,950 ± 112 (-8.8%) | 48.7 ± 1.5 (+15.1%) | 1320 ± 31 (+5.6%) |
| tk-mybatis | 12,350 ± 138 (-3.9%) | 8,410 ± 87 (-3.6%) | 45.1 ± 1.3 (+6.6%) | 1280 ± 28 (+2.4%) |
性能分析:
- MyBatis 原生性能最优:无额外抽象层,直接执行 SQL
- MyBatis Plus 性能损耗最大:功能丰富带来一定开销,特别是在复杂条件构造时
- tk-mybatis 性能损耗最小:轻量级设计,对原生 MyBatis 侵入小
- 实际影响有限:在普通业务场景中(QPS<1000),性能差异通常小于 10ms,可忽略不计
3.3 代码量与开发效率对比
场景:实现用户管理模块(增删改查、分页、条件搜索)
| 框架 | Mapper XML 行数 | Java 代码行数 | 配置复杂度 | 开发时间(小时) |
|---|---|---|---|---|
| MyBatis | 68 | 125 | 高 | 4.5 |
| MyBatis Plus | 0 | 45 | 低 | 1.5 |
| tk-mybatis | 0 | 65 | 中 | 2.0 |
效率分析:
- MyBatis Plus 开发效率最高:省去 80% 重复代码,特别是单表操作
- tk-mybatis 次之:简化了基础 CRUD,但复杂查询仍需手动处理
- 原生 MyBatis 最低效:但对复杂 SQL 有更好的控制力
- 维护成本:增强框架在简单场景维护成本低,复杂场景可能因黑盒逻辑增加调试难度
四、应用场景分析:何时选择哪个框架?
4.1 MyBatis 适用场景
推荐场景:
- 复杂 SQL 项目:报表系统、数据仓库、复杂分析查询
- 遗留系统改造:已有大量 MyBatis XML 文件,迁移成本高
- 性能极度敏感:高频交易系统、核心计费模块
- 技术栈统一要求:国际化团队,需保持技术栈简洁
案例:某银行核心交易系统
// 需要高度定制化SQL,考虑性能和事务
@Repository
public class TransactionMapper {
@Select({
"<script>",
"SELECT t.*, a.balance as account_balance",
"FROM transactions t",
"JOIN accounts a ON t.account_id = a.id",
"WHERE t.create_time BETWEEN #{startTime} AND #{endTime}",
"<if test='accountId != null'>",
" AND t.account_id = #{accountId}",
"</if>",
"<if test='minAmount != null'>",
" AND t.amount >= #{minAmount}",
"</if>",
"ORDER BY t.create_time DESC",
"LIMIT #{offset}, #{limit}",
"</script>"
})
@Results(id = "transactionResult", value = {
@Result(property = "id", column = "id"),
@Result(property = "amount", column = "amount", typeHandler = MoneyTypeHandler.class),
@Result(property = "account", column = "account_id",
one = @One(select = "com.example.mapper.AccountMapper.selectById"))
})
List<Transaction> findComplexTransactions(
@Param("startTime") Date startTime,
@Param("endTime") Date endTime,
@Param("accountId") Long accountId,
@Param("minAmount") BigDecimal minAmount,
@Param("offset") int offset,
@Param("limit") int limit
);
}
选择理由:
- 完全控制 SQL,优化执行计划
- 避免增强框架的额外开销
- 与现有技术栈无缝集成
- 复杂结果映射更灵活
4.2 MyBatis Plus 适用场景
推荐场景:
- 快速开发项目:内部管理系统、SaaS 应用、MVP 产品
- 标准化 CRUD 服务:用户中心、商品管理、订单基础服务
- 国产化环境:需要中文文档、社区支持
- 需要高级特性:多租户、逻辑删除、自动填充等
案例:电商平台商品中心
@Data
@TableName("products")
public class Product {
@TableId(type = IdType.ASSIGN_ID) // 雪花ID
private Long id;
private String name;
private String description;
private BigDecimal price;
private Integer stock;
private String category;
private String imageUrl;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableLogic
private Integer isDeleted;
// 冗余字段 - 避免关联查询
@TableField(exist = false)
private List<ProductImage> images;
}
@Service
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
implements ProductService {
private final ProductImageService productImageService;
@Override
@Transactional
public boolean saveWithImages(Product product) {
// 1. 保存商品
boolean saved = save(product);
if (!saved) return false;
// 2. 批量保存图片
List<ProductImage> images = product.getImages();
if (CollectionUtils.isNotEmpty(images)) {
images.forEach(img -> img.setProductId(product.getId()));
productImageService.saveBatch(images);
}
return true;
}
@Override
public Page<ProductVO> searchProducts(ProductQuery query) {
// 构建条件
LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Product::getIsDeleted, 0);
if (StringUtils.isNotBlank(query.getKeyword())) {
wrapper.and(w -> w
.like(Product::getName, query.getKeyword())
.or()
.like(Product::getDescription, query.getKeyword())
);
}
if (StringUtils.isNotBlank(query.getCategory())) {
wrapper.eq(Product::getCategory, query.getCategory());
}
if (query.getMinPrice() != null) {
wrapper.ge(Product::getPrice, query.getMinPrice());
}
if (query.getMaxPrice() != null) {
wrapper.le(Product::getPrice, query.getMaxPrice());
}
wrapper.orderByDesc(Product::getCreateTime);
// 分页查询
Page<Product> page = new Page<>(query.getPageNum(), query.getPageSize());
Page<Product> productPage = page(page, wrapper);
// 转换为VO,补充图片等信息
return productPage.convert(product -> {
ProductVO vo = ProductVO.fromEntity(product);
vo.setImages(productImageService.listByProductId(product.getId()));
return vo;
});
}
// 多租户查询
@Override
public List<Product> listByTenant(Long tenantId) {
return list(new LambdaQueryWrapper<Product>()
.eq(Product::getTenantId, tenantId)
.eq(Product::getIsDeleted, 0));
}
}
选择理由:
- 大幅减少样板代码,提升开发速度
- 内置分页、逻辑删除等企业级特性
- Lambda 表达式保证代码可重构性
- 完善的中文文档和国内社区支持
- 与 Spring Boot 深度集成
4.3 tk-mybatis 适用场景
推荐场景:
- 轻量级项目:小型应用、微服务中的简单模块
- 国际化团队:需要英文文档,避免中文技术栈锁定
- 已有 MyBatis 基础:希望渐进式增强,而非完全替换
- 资源受限环境:IoT 设备、边缘计算节点等对 jar 包大小敏感的场景
案例:IoT 设备管理服务
// 轻量级实体
public class Device {
private String deviceId; // 主键
private String name;
private String type;
private String status; // ONLINE/OFFLINE
private String location;
private Date lastActiveTime;
private String tenantId; // 多租户
// getters/setters
}
// 专用Mapper
public interface DeviceMapper extends Mapper<Device>, MySqlMapper<Device> {
// 扩展方法
@Select("SELECT * FROM devices WHERE tenant_id = #{tenantId} AND status = 'ONLINE'")
List<Device> selectOnlineByTenant(@Param("tenantId") String tenantId);
@Update("UPDATE devices SET status = 'OFFLINE' WHERE last_active_time < #{beforeTime}")
void offlineInactiveDevices(@Param("beforeTime") Date beforeTime);
}
// 服务层
@Service
@RequiredArgsConstructor
public class DeviceService {
private final DeviceMapper deviceMapper;
private final TenantContext tenantContext;
// 基础CRUD使用通用方法
public Device getDevice(String deviceId) {
return deviceMapper.selectByPrimaryKey(deviceId);
}
public List<Device> searchDevices(DeviceQuery query) {
Example example = new Example(Device.class);
Example.Criteria criteria = example.createCriteria();
// 多租户隔离
criteria.andEqualTo("tenantId", tenantContext.getCurrentTenant());
if (StringUtils.isNotEmpty(query.getName())) {
criteria.andLike("name", "%" + query.getName() + "%");
}
if (StringUtils.isNotEmpty(query.getType())) {
criteria.andEqualTo("type", query.getType());
}
if (StringUtils.isNotEmpty(query.getStatus())) {
criteria.andEqualTo("status", query.getStatus());
}
example.orderBy(query.getOrderBy()).orderBy(query.getSort());
// 分页
PageHelper.startPage(query.getPageNum(), query.getPageSize());
return deviceMapper.selectByExample(example);
}
@Scheduled(fixedRate = 300000) // 5分钟
public void checkDeviceStatus() {
// 自动下线长时间无活动的设备
Date offlineThreshold = new Date(System.currentTimeMillis() - 10 * 60 * 1000); // 10分钟
deviceMapper.offlineInactiveDevices(offlineThreshold);
// 记录日志
log.info("Device status check completed at {}", new Date());
}
}
选择理由:
- 轻量级,jar 包小,启动快
- 保留 MyBatis 原生体验,学习成本低
- 国际化支持好,适合海外团队
- 对资源受限环境友好
- 侵入性小,可渐进式采用
五、迁移策略与混合架构
5.1 从 MyBatis 到增强框架的迁移路径
渐进式迁移策略:
graph LR
A[纯MyBatis] -->|新增模块使用| B[混合架构]
B -->|核心模块重写| C[全量增强框架]
实施步骤:
- 评估现有代码:识别可复用的 Mapper 和实体
- 创建适配层:保留原有接口,内部实现替换
// 旧接口保持不变 public interface UserMapper { User findById(Long id); List<User> findByCondition(Map<String, Object> params); } // 新实现 @Repository public class UserMapperImpl implements UserMapper { @Autowired private UserPlusMapper userPlusMapper; // MyBatis Plus 实现 @Override public User findById(Long id) { return userPlusMapper.selectById(id); } @Override public List<User> findByCondition(Map<String, Object> params) { LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); if (params.containsKey("name")) { wrapper.like(User::getName, params.get("name")); } // ...其他条件 return userPlusMapper.selectList(wrapper); } } - 分模块迁移:先迁移非核心模块,验证稳定性
- 性能监控:迁移前后对比关键指标(响应时间、GC 频率)
- 逐步替换:当新模块稳定后,替换核心模块
5.2 混合架构:优势互补的实践
在复杂系统中,单一框架往往难以满足所有需求。混合架构可发挥各自优势:
推荐模式:
- 核心交易:原生 MyBatis(精确控制 SQL 和事务)
- 管理后台:MyBatis Plus(快速开发,丰富特性)
- 基础数据:tk-mybatis(轻量高效)
统一数据访问层:
// 统一DAO接口
public interface UserDao {
User getById(Long id);
List<User> searchUsers(UserQuery query);
Page<User> pageUsers(int pageNum, int pageSize);
boolean save(User user);
boolean update(User user);
boolean delete(Long id);
}
// 多实现注册
@Configuration
public class DaoConfig {
@Bean
@Primary
@ConditionalOnProperty(prefix = "dao", name = "type", havingValue = "mybatis-plus")
public UserDao mybatisPlusUserDao(UserMapper userMapper) {
return new MybatisPlusUserDao(userMapper);
}
@Bean
@ConditionalOnProperty(prefix = "dao", name = "type", havingValue = "tk-mybatis")
public UserDao tkMybatisUserDao(tkUserMapper userMapper) {
return new TkMybatisUserDao(userMapper);
}
@Bean
@ConditionalOnProperty(prefix = "dao", name = "type", havingValue = "native")
public UserDao nativeMybatisUserDao(SqlSessionTemplate sqlSession) {
return new NativeMybatisUserDao(sqlSession);
}
}
配置切换:
# application.yml
dao:
type: mybatis-plus # 可切换为 tk-mybatis 或 native
优势:
- 模块化设计,技术栈解耦
- 按需选择最优框架
- 平滑迁移,降低风险
- 团队可并行使用不同技术栈
六、技术选型决策树
graph TD
A[项目需求分析] --> B{SQL复杂度}
B -->|高<br>复杂报表/分析查询| C[选择原生MyBatis]
B -->|低-中<br>标准CRUD| D{团队环境}
D -->|国内团队<br>中文支持需求| E{功能需求}
E -->|多租户/逻辑删除/AR模式| F[选择MyBatis Plus]
E -->|仅需基础CRUD| G[选择tk-mybatis]
D -->|国际团队<br>英文文档需求| H{资源限制}
H -->|资源受限<br>边缘设备/IoT| I[选择tk-mybatis]
H -->|资源充足| J[评估MyBatis Plus国际版]
C --> K[保留原生MyBatis]
F --> L[全面采用MyBatis Plus]
G --> M[采用tk-mybatis]
I --> N[采用tk-mybatis]
J --> O[考虑MyBatis Plus或混合架构]
七、未来趋势与建议
7.1 技术演进方向
-
MyBatis Plus:
- 强化国际化支持,完善英文文档
- 优化性能,减少反射开销
- 增强云原生支持(Kubernetes 配置、Service Mesh 集成)
- 与 Jakarta EE 标准深度融合
-
tk-mybatis:
- 增加更多数据库方言支持
- 轻量级分页和逻辑删除内置
- 与 Quarkus、Micronaut 等新框架更好集成
- 增强类型安全(通过注解处理器)
-
MyBatis Core:
- 响应式编程支持(Reactive MyBatis)
- 原生 GraalVM 支持
- 增强类型处理器系统
- 简化配置(减少 XML 依赖)
7.2 选型建议
根据项目阶段:
- 初创项目/快速验证:MyBatis Plus(开发速度优先)
- 成熟产品/重构:混合架构(核心模块原生 MyBatis,辅助模块增强框架)
- 维护遗留系统:渐进式迁移,先 tk-mybatis 后 MyBatis Plus
根据团队构成:
- 国内团队:MyBatis Plus(完善中文生态)
- 国际团队:tk-mybatis(国际化支持好)
- 混合团队:核心模块原生 MyBatis,统一技术栈
根据系统特性:
- 高并发核心系统:原生 MyBatis + 手动优化
- 管理后台/内部系统:MyBatis Plus
- 微服务基础数据:tk-mybatis
- IoT/边缘计算:tk-mybatis(轻量级)
八、结语:合适的技术才是最好的技术
在 MyBatis 生态中,没有"最好"的框架,只有"最合适"的框架。MyBatis 提供了基础与自由,MyBatis Plus 带来了效率与功能,tk-mybatis 保持了轻量与兼容。三者并非竞争关系,而是互补共生的技术选择。
核心建议:
- 不要为了用框架而用框架:评估实际需求,避免过度设计
- 保持架构的可进化性:设计良好的抽象层,降低迁移成本
- 性能与效率的权衡:在 80% 的场景,开发效率比 10% 的性能提升更重要
- 团队熟悉度优先:熟悉 MyBatis 的团队使用 tk-mybatis 学习成本更低
- 渐进式演进:从简单开始,逐步引入增强特性
正如 MyBatis 创始人 Clinton Begin 所言:"The best framework is the one that gets out of your way when you need it to."(最好的框架是在你需要时不会妨碍你的框架。)
选择适合你项目的框架,让它成为你构建卓越软件的助力,而非束缚。
附录:快速参考指南
常用操作对比
插入数据:
// MyBatis
userMapper.insert(user);
// MyBatis Plus
userMapper.insert(user); // 或 user.insert()
// tk-mybatis
userMapper.insert(user);
条件查询:
// MyBatis
List<User> users = userMapper.selectByCondition(map);
// MyBatis Plus
List<User> users = userMapper.selectList(
new LambdaQueryWrapper<User>()
.eq(User::getAge, 25)
.like(User::getName, "张")
);
// tk-mybatis
Example example = new Example(User.class);
example.createCriteria()
.andEqualTo("age", 25)
.andLike("name", "张%");
List<User> users = userMapper.selectByExample(example);
分页查询:
// MyBatis + PageHelper
PageHelper.startPage(1, 10);
List<User> users = userMapper.selectAll();
// MyBatis Plus
Page<User> page = new Page<>(1, 10);
userMapper.selectPage(page, null);
// tk-mybatis + PageHelper
PageHelper.startPage(1, 10);
List<User> users = userMapper.selectAll();
学习资源
MyBatis:
MyBatis Plus:
- 官方文档(中文):https://baomidou.com/
- GitHub:https://github.com/baomidou/mybatis-plus
tk-mybatis:
- 文档(中/英文):http://mybatis.tk/
- GitHub:https://github.com/abel533/Mapper
评论