使用MyBatis注解方式的完整示例,涵盖CRUD、动态SQL、分页、事务管理等场景,并附详细注释和对比表格

发布于:2025-05-01 ⋅ 阅读:(7) ⋅ 点赞:(0)

以下是使用MyBatis注解方式的完整示例,涵盖CRUD、动态SQL、分页、事务管理等场景,并附详细注释和对比表格:
在这里插入图片描述


项目结构

mybatis-annotation-demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com.example/
│   │   │       ├── entity/
│   │   │       ├── mapper/
│   │   │       ├── service/
│   │   │       └── config/
│   │   └── resources/
│   │       ├── mybatis-config.xml
│   │       └── schema.sql
│   └── test/
│       └── java/
│           └── com.example/
│               └── MyBatisTest.java
├── pom.xml

1. Maven依赖(pom.xml)

<dependencies>
    <!-- MyBatis核心 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.10</version>
    </dependency>
    <!-- 数据库驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.30</version>
    </dependency>
    <!-- JUnit测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2. 数据库表(schema.sql)

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL
);

CREATE TABLE order (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT,
    amount DECIMAL(10,2) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES user(id)
);

3. 实体类(User.java & Order.java)

// User.java
public class User {
    private Long id;
    private String name;
    private String email;
    // Getters and Setters
}

// Order.java
public class Order {
    private Long id;
    private Long userId;
    private BigDecimal amount;
    // Getters and Setters
}

4. MyBatis全局配置(mybatis-config.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.example.mapper"/>
    </mappers>
</configuration>

5. Mapper接口(UserMapper.java)

import org.apache.ibatis.annotations.*;
import java.util.List;

public interface UserMapper {

    // === 基础CRUD ===
    @Insert("INSERT INTO user (name, email) VALUES (#{name}, #{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insertUser(User user); // 新增用户

    @Select("SELECT * FROM user WHERE id = #{id}")
    User selectUserById(Long id); // 根据ID查询

    @Update("UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id}")
    void updateUser(User user); // 更新用户

    @Delete("DELETE FROM user WHERE id = #{id}")
    void deleteUser(Long id); // 删除用户

    // === 动态SQL ===
    @Select("SELECT * FROM user WHERE name LIKE CONCAT('%', #{keyword}, '%')")
    List<User> searchUsersByName(@Param("keyword") String keyword); // 模糊查询

    // === 关联查询 ===
    @Results({
        @Result(id = true, column = "id", property = "id"),
        @Result(column = "name", property = "name"),
        @Result(column = "email", property = "email"),
        @Result(property = "orders", 
                column = "id", 
                javaType = List.class,
                many = @Many(select = "com.example.mapper.OrderMapper.selectOrdersByUserId"))
    })
    @Select("SELECT * FROM user WHERE id = #{id}")
    User selectUserWithOrders(Long id); // 通过ID查询用户及其订单

    // === 分页 ===
    @Select("SELECT * FROM user LIMIT #{offset}, #{limit}")
    List<User> selectUsersByPage(
        @Param("offset") int offset,
        @Param("limit") int limit
    );

    // === 事务管理 ===
    @Insert("INSERT INTO user (name, email) VALUES (#{name}, #{email})")
    @SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", 
              before = false, resultType = Long.class)
    void insertWithTransaction(User user); // 带事务的插入
}

6. Service层(UserService.java)

import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class UserService {
    private final SqlSessionFactory sqlSessionFactory;

    public UserService(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    public void addUser(User user) {
        try (SqlSession session = sqlSessionFactory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);
            mapper.insertUser(user);
            session.commit();
        }
    }

    public List<User> searchUsers(String keyword) {
        try (SqlSession session = sqlSessionFactory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);
            return mapper.searchUsersByName(keyword);
        }
    }

    // 其他方法类似...
}

7. 测试类(MyBatisTest.java)

import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

public class MyBatisTest {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void setup() {
        sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(getClass().getResourceAsStream("/mybatis-config.xml"));
    }

    @Test
    public void testInsert() {
        User user = new User();
        user.setName("John");
        user.setEmail("john@example.com");
        
        UserService service = new UserService(sqlSessionFactory);
        service.addUser(user);
        System.out.println("Inserted user ID: " + user.getId());
    }

    // 其他测试方法...
}

8. 核心注解对比表

注解 作用 使用场景 示例
@Insert 定义插入操作 新增数据 @Insert("INSERT INTO user (name, email) VALUES (#{name}, #{email})")
@Select 定义查询操作 查询单条或多条数据 @Select("SELECT * FROM user WHERE id = #{id}")
@Update 定义更新操作 修改数据 @Update("UPDATE user SET name = #{name} WHERE id = #{id}")
@Delete 定义删除操作 删除数据 @Delete("DELETE FROM user WHERE id = #{id}")
@Param 标记参数名 多参数传递时指定参数名 @Param("keyword") String keyword
@Options 配置操作选项(如主键回填) 需要自动生成主键时 @Options(useGeneratedKeys = true, keyProperty = "id")
@Results 定义复杂结果映射 处理多表关联查询(如嵌套对象) @Result(property = "orders", column = "id", many = @Many(...))
@SelectKey 定义主键生成逻辑 需要自定义主键生成逻辑(如UUID) @SelectKey(statement = "SELECT UUID()", keyProperty = "id", before = true)
@ResultMap 引用外部定义的@Results 复用结果映射配置 @Select("...") @ResultMap("userWithOrders")

9. 关键差异总结

特性 注解方式 XML方式
代码耦合度 与Java代码强耦合,注解直接写在方法上 XML文件独立,与Java代码解耦
可读性 简单查询可读性高,复杂查询易混乱 XML结构清晰,适合复杂SQL
动态SQL支持 需结合@Select拼接字符串,灵活性有限 XML支持<if>, <choose>, <foreach>等标签
维护成本 小型项目维护简单,大型项目易产生代码冗余 XML集中管理SQL,便于统一维护
性能优化 难以复用SQL片段 XML可定义<sql>片段复用
适用场景 简单CRUD操作、快速开发 复杂查询、多表关联、企业级项目

10. 最佳实践建议

  1. 简单场景:优先使用注解(如@Select/@Insert),代码简洁。
  2. 复杂场景:改用XML(如动态SQL、多表关联),避免注解拼接字符串的可读性问题。
  3. 分页与分页:注解适合固定分页逻辑,复杂分页建议结合RowBounds或自定义插件。
  4. 事务管理:通过Spring AOP或SqlSession显式控制事务边界。
  5. 结果映射:复杂对象关联建议使用XML的<resultMap>,避免注解嵌套过深。