1. MyBatis单表增删改查方法解析
作为Java开发者最常用的ORM框架之一,MyBatis在单表操作场景下的灵活性和高效性一直备受青睐。今天我们就来深入探讨MyBatis在单表CRUD操作中的各种实现方式,包括传统XML配置、注解开发以及MyBatis-Plus的增强用法。
1.1 基础环境准备
首先确保项目中已经引入MyBatis核心依赖。对于Maven项目,pom.xml中需要添加:
xml复制<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
如果使用Spring Boot集成,可以直接使用starter:
xml复制<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
数据库表我们以用户表为例:
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
对应的Java实体类:
java复制public class User {
private Long id;
private String username;
private String password;
private String email;
private Date createTime;
// getters and setters
}
1.2 传统XML映射方式
1.2.1 查询操作
在UserMapper.xml中定义查询语句:
xml复制<!-- 根据ID查询 -->
<select id="selectById" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 查询所有用户 -->
<select id="selectAll" resultType="com.example.entity.User">
SELECT * FROM user
</select>
<!-- 条件查询 -->
<select id="selectByCondition" resultType="com.example.entity.User">
SELECT * FROM user
<where>
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="email != null and email != ''">
AND email = #{email}
</if>
</where>
</select>
对应的Mapper接口:
java复制public interface UserMapper {
User selectById(Long id);
List<User> selectAll();
List<User> selectByCondition(User user);
}
1.2.2 插入操作
xml复制<!-- 插入用户 -->
<insert id="insert" parameterType="com.example.entity.User"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO user(username, password, email)
VALUES(#{username}, #{password}, #{email})
</insert>
注意:useGeneratedKeys和keyProperty属性配合使用可以获取数据库自动生成的主键值
1.2.3 更新操作
xml复制<!-- 更新用户 -->
<update id="update" parameterType="com.example.entity.User">
UPDATE user
SET username = #{username},
password = #{password},
email = #{email}
WHERE id = #{id}
</update>
<!-- 动态更新 -->
<update id="updateSelective" parameterType="com.example.entity.User">
UPDATE user
<set>
<if test="username != null">username = #{username},</if>
<if test="password != null">password = #{password},</if>
<if test="email != null">email = #{email},</if>
</set>
WHERE id = #{id}
</update>
1.2.4 删除操作
xml复制<!-- 根据ID删除 -->
<delete id="deleteById" parameterType="long">
DELETE FROM user WHERE id = #{id}
</delete>
<!-- 批量删除 -->
<delete id="deleteBatch" parameterType="list">
DELETE FROM user WHERE id IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
1.3 注解开发方式
对于简单的单表操作,可以使用注解替代XML配置:
java复制public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Long id);
@Insert("INSERT INTO user(username, password, email) " +
"VALUES(#{username}, #{password}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
@Update("UPDATE user SET username=#{username}, " +
"password=#{password}, email=#{email} WHERE id=#{id}")
int update(User user);
@Delete("DELETE FROM user WHERE id=#{id}")
int deleteById(Long id);
// 动态SQL需要通过@SelectProvider等注解实现
@SelectProvider(type = UserSqlProvider.class, method = "selectByCondition")
List<User> selectByCondition(User user);
}
对应的SQL提供类:
java复制public class UserSqlProvider {
public String selectByCondition(User user) {
return new SQL() {{
SELECT("*");
FROM("user");
if (user.getUsername() != null) {
WHERE("username LIKE CONCAT('%', #{username}, '%')");
}
if (user.getEmail() != null) {
WHERE("email = #{email}");
}
}}.toString();
}
}
1.4 MyBatis-Plus增强用法
MyBatis-Plus是MyBatis的增强工具,可以极大简化单表CRUD操作:
1.4.1 基础配置
添加依赖:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
Mapper接口继承BaseMapper:
java复制public interface UserMapper extends BaseMapper<User> {
// 已经内置了大量基础CRUD方法
}
1.4.2 基本CRUD操作
java复制// 查询
User user = userMapper.selectById(1L);
List<User> users = userMapper.selectList(
new QueryWrapper<User>().like("username", "admin"));
// 插入
User newUser = new User();
newUser.setUsername("test");
newUser.setPassword("123456");
userMapper.insert(newUser);
// 更新
User updateUser = new User();
updateUser.setId(1L);
updateUser.setEmail("new@example.com");
userMapper.updateById(updateUser);
// 删除
userMapper.deleteById(1L);
1.4.3 条件构造器
MyBatis-Plus提供了强大的条件构造器:
java复制// 复杂查询
List<User> userList = userMapper.selectList(
new QueryWrapper<User>()
.select("id", "username", "email")
.like("username", "张")
.between("create_time", startDate, endDate)
.orderByDesc("create_time")
);
// 更新条件
userMapper.update(
new User().setPassword("newPassword"),
new UpdateWrapper<User>()
.eq("username", "admin")
.or()
.eq("email", "admin@example.com")
);
1.5 性能优化与注意事项
1.5.1 批量操作优化
对于批量插入,MyBatis提供了批量执行器:
java复制// 开启批量模式
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
for (int i = 0; i < 1000; i++) {
User user = new User();
// 设置属性...
mapper.insert(user);
}
sqlSession.commit();
} finally {
sqlSession.close();
}
MyBatis-Plus的批量操作:
java复制List<User> userList = new ArrayList<>();
// 添加用户数据...
// 批量插入
userService.saveBatch(userList, 1000); // 每1000条提交一次
1.5.2 缓存使用
MyBatis提供了一级缓存和二级缓存:
xml复制<!-- 开启二级缓存 -->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
提示:一级缓存是SqlSession级别的,默认开启;二级缓存是Mapper级别的,需要手动配置
1.5.3 常见问题
-
主键回填问题:
- XML方式:使用useGeneratedKeys和keyProperty
- 注解方式:使用@Options注解
- MyBatis-Plus:自动处理主键回填
-
字段映射问题:
- 数据库字段user_name对应Java属性userName
- 可以使用@TableField注解指定映射关系
-
SQL注入防护:
- 永远不要直接拼接SQL参数
- 使用#{}而不是${}进行参数绑定
-
性能监控:
- 集成p6spy打印真实SQL
- 使用MyBatis-Plus的性能分析插件
java复制@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
interceptor.setMaxTime(1000); // SQL执行最大时长,超过自动停止运行
interceptor.setFormat(true); // 是否格式化SQL
return interceptor;
}
1.6 高级特性应用
1.6.1 类型处理器
自定义类型处理器处理特殊数据类型:
java复制@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptTypeHandler extends BaseTypeHandler<String> {
// 实现加解密逻辑
}
在映射中使用:
xml复制<result column="password" property="password"
typeHandler="com.example.handler.EncryptTypeHandler"/>
1.6.2 插件开发
实现分页插件:
java复制@Intercepts(@Signature(type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}))
public class MyPaginationInterceptor implements Interceptor {
// 实现分页逻辑
}
注册插件:
xml复制<plugins>
<plugin interceptor="com.example.plugin.MyPaginationInterceptor"/>
</plugins>
1.6.3 多租户实现
使用MyBatis-Plus的多租户插件:
java复制@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(
new TenantLineHandler() {
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public Expression getTenantId() {
return new StringValue("当前租户ID");
}
@Override
public boolean ignoreTable(String tableName) {
return !"user".equalsIgnoreCase(tableName);
}
}));
return interceptor;
}
1.7 最佳实践总结
-
项目结构组织:
- 按功能模块分包,而不是按技术分层
- 保持Mapper接口与XML文件同名同包
-
SQL编写规范:
- 避免使用SELECT *,明确列出所需字段
- 复杂查询拆分为多个简单查询,利用MyBatis的关联映射
-
事务管理:
- 在Service层使用@Transactional注解
- 合理设置事务隔离级别和传播行为
-
代码生成:
- 使用MyBatis Generator或MyBatis-Plus代码生成器
- 自定义模板生成符合项目规范的代码
java复制// MyBatis-Plus代码生成器配置示例
AutoGenerator generator = new AutoGenerator(dataSourceConfig);
generator.setGlobalConfig(globalConfig);
generator.setPackageInfo(packageConfig);
generator.setStrategy(strategyConfig);
generator.setTemplate(templateConfig);
generator.execute();
- 测试验证:
- 编写Mapper层单元测试
- 使用@SpringBootTest进行集成测试
- 验证SQL执行计划和性能
java复制@SpringBootTest
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testSelectById() {
User user = userMapper.selectById(1L);
assertNotNull(user);
}
}
在实际项目中,根据业务复杂度选择适合的开发方式。简单项目可以使用注解或MyBatis-Plus快速开发,复杂项目建议使用XML配置保持SQL的可维护性。无论哪种方式,都要注意SQL性能和安全问题,合理使用MyBatis提供的各种特性来提升开发效率和系统性能。
