Mybatis @Param注解的作用

本文介绍了在使用MyBatis框架时如何正确处理带有多个输入参数的SQL查询,特别是当这些参数用于复杂查询如分页时。文章通过一个具体的例子解释了如何避免参数名称丢失的问题,并展示了如何使用@Param注解为输入参数指定名称。

在刚使用Mybatis的时候,我们经常会犯一个错误。如下

一个秒杀网站的Dao层中的方法

public interface SeckillDao {
    /**
     * 根据id查询秒杀的商品信息
     * @param seckillId
     * @return
     */
    @Select({"SELECT * FROM seckill WHERE seckill_id=#{seckillId}"})
    Seckill queryById(long seckillId);

    /**
     * 根据偏移量查询秒杀商品列表
     * @param a
     * @param b
     * @return
     */
    @Select({"SELECT * FROM seckill ORDER BY create_time DESC limit #{a},#{b} "})
    List<Seckill> queryAll( int offset, int limit);
}  

这是一个常见的用注解进行开发的DAO层代码,现在我们用Junit来测试一下。

/**
 * 配置spring和junit整合,这样junit在启动时就会加载spring容器
 */
@RunWith(SpringJUnit4ClassRunner.class)
//告诉junit spring的配置文件
@ContextConfiguration({"classpath:spring/spring-dao.xml"})
public class SeckillDaoTest {

    //注入Dao实现类依赖
    @Resource
    private SeckillDao seckillDao;


    @Test
    public void queryById() throws Exception {
        long seckillId=1000;
        Seckill seckill=seckillDao.queryById(seckillId);
        System.out.println(seckill.getName());
        System.out.println(seckill);
    }

    @Test
    public void queryAll() throws Exception {

        List<Seckill> seckills=seckillDao.queryAll(0,100);
        for (Seckill seckill : seckills) {
            System.out.println(seckill);
        }
    }

当我们运行queryId()这个测试方法时,会显示通过测试。
但是我们运行第二个测试方法时,Junit会显示报错。

Parameter ‘a’ not found

参数a没有找到,为什么会报这种错误呢?

因为Java设计时,并没有保存形参的记录

queryAll( int offset, int limit)   
在运行期变成---> queryAll(arg0, arg1)

所以当你的方法只有一个参数的时候,你可以随意使用.但是如果你有多个参数的话,你就必须告诉mybatis你的参数分别叫什么名字。这样你传入参数的时候,mybatis才能通过参数名字将数据传入#{}中。

mybatis就提供了@Param这个注解来完成命名

SELECT * FROM seckill ORDER BY create_time DESC limit #{a},#{b} 表示sql语句要接受2个参数,一个参数名是a,一个参数名是b

修改错误代码

    /**
     * 根据偏移量查询秒杀商品列表
     * @param a
     * @param b
     * @return
     */
    @Select({"SELECT * FROM seckill ORDER BY create_time DESC limit #{a},#{b} "})
    List<Seckill> queryAll(@Param("a") int offset, @Param("b") int limit);
}  

给入参int offset 命名为a , int limit命名为b,然后sql语句SELECT * FROM seckill ORDER BY create_time DESC limit #{a},#{b} 中就可以根据a和b得到参数值了

<think>我们正在讨论MyBatis中的@Select注解。根据用户的问题,我们需要解释@Select注解的用途和使用方法。 引用[1]提到:@Select是Mybatis的三种继承方式之一(另外两种是@Provider和xml映射文件)。引用[4]展示了一个简单的例子:在接口方法上使用@Select注解并直接入SQL语句。 引用[3]和[5]展示了更复杂的用法,比如在@Select注解动态SQL(使用<script>标签)以及多表连接查询。 因此,我们可以这样组织回答: 1. 用途:@Select注解用于在MyBatis的Mapper接口方法上直接定义SQL查询语句,避免了XML映射文件的编。 2. 基本用法:在接口方法上添加@Select注解,并在注解入SQL语句。 3. 动态SQL:如果需要条件判断等动态SQL,可以使用<script>包裹SQL语句,并在其中使用MyBatis的动态SQL标签(如<if>)。 4. 参数传递:可以通过#{参数名}的方式引用方法参数。如果方法有多个参数,可以使用@Param注解指定参数名。 同时,我们注意到引用[2]提到一个常见错误:当使用IN语句时,如果参数是集合,需要特别注意参数名的指定,否则会出现参数找不到的错误。 因此,在回答中,我们将包括: - 基本示例 - 动态SQL示例 - 参数传递的注意事项 最后,根据系统指令,我们需要在回答末尾生成相关问题。 注意:用户的问题是关于@Select注解的,所以我们聚焦于此。</think>### MyBatis @Select 注解详解 #### 一、用途与作用 `@Select` 是 MyBatis 提供的核心注解之一,主要用于**简化 SQL 映射配置**。其核心作用包括: 1. **替代 XML 映射文件**:直接在 Java 接口方法上编 SQL 语句,无需额外 XML 文件[^4] 2. **声明查询操作**:标注在 Mapper 接口方法上,声明该方法执行查询操作 3. **支持动态 SQL**:结合 `<script>` 标签实现条件查询(如 `WHERE` 子句动态拼接)[^3] 4. **提高开发效率**:适用于简单 SQL 场景,减少配置复杂度 #### 二、基础使用方法 ```java public interface UserMapper { // 1. 基础查询 @Select("SELECT id, name, age FROM user WHERE id = #{userId}") User getUserById(int userId); // 2. 多参数查询(使用@Param) @Select("SELECT * FROM product WHERE category = #{cat} AND price > #{minPrice}") List<Product> findProducts(@Param("cat") String category, @Param("minPrice") double minPrice); } ``` **参数说明**: - `#{参数名}`:MyBatis 参数占位符,自动防 SQL 注入 - `@Param`:当方法有多个参数时**必须使用**,否则报参数绑定错误[^2] #### 三、动态 SQL 实现 通过 `<script>` 标签支持条件判断: ```java @Select("<script>" + "SELECT * FROM orders WHERE status = 'ACTIVE'" + "<if test='amount != null'> AND total_amount > #{amount} </if>" + "<if test='startDate != null'> AND create_time >= #{startDate} </if>" + "</script>") List<Order> findActiveOrders(@Param("amount") BigDecimal minAmount, @Param("startDate") Date startDate); ``` **动态标签支持**: - `<if>`:条件判断 - `<foreach>`:循环遍历(常用于 `IN` 语句) - `<choose>/<when>/<otherwise>`:多路选择 #### 四、特殊场景处理 1. **`IN` 语句的正确用法**: ```java @Select("<script>" + "SELECT * FROM camera WHERE id IN " + "<foreach item='id' collection='cameraIds' open='(' separator=',' close=')'>" + "#{id}" + "</foreach>" + "</script>") List<Camera> findByIds(@Param("cameraIds") List<Long> ids); // 必须用@Param定义集合名 ``` **避免错误**:直接 `IN (#{ids})` 会导致 `Parameter 'item' not found` 异常[^2] 2. **多表连接查询**: ```java @Select("SELECT u.*, d.department_name " + "FROM user u INNER JOIN department d ON u.dept_id = d.id " + "WHERE u.status = 1") List<UserVO> getActiveUsersWithDept(); ``` #### 五、适用场景与限制 | 场景类型 | 推荐使用 | 注意事项 | |----------------|----------|------------------------------| | 简单静态 SQL | ✅ 推荐 | SQL 长度不宜超过 3 行 | | 复杂动态 SQL | ⚠️ 谨慎 | 需用 `<script>` 维护性较差 | | 多表关联查询 | ⚠️ 谨慎 | 建议拆分为多个方法 | | 大批量结果处理 | ❌ 不推荐 | 需用 XML 配置结果集映射 | > **最佳实践建议**: > - 简单查询(单表操作、固定条件)优先使用 `@Select` > - 复杂业务查询(多表关联、动态条件嵌套)建议使用 XML 映射文件[^1][^3]
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值