Mybatis動態sql中@Param使用詳解

我的個人網站:
http://riun.xyz


Mybatis中的@param註解的使用場景:
1、方法有多個參數
2、方法參數要取別名
3、XML 中的 SQL 使用了 $
4、動態sql中參數是非自定義pojo類型

前三種,相信大家都非常熟練,這裏不再多說,這裏主要說下第四種。
方法的參數爲非自定義pojo類型,且使用了動態sql,那麼就需要在參數前加上@Param註解。

測試:(此處使用SpringBoot2.0+ 、Mybatis-Plus)

數據庫數據:

在這裏插入圖片描述

代碼:

pojo:

/**
 * @author: HanXu
 * on 2019/12/18
 * Class description:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Test {
    private Integer id;
    private String name;
    private Integer age;
    private Integer num;
}

mapper接口:

/**
 * @author: HanXu
 * on 2019/12/18
 * Class description:
 */
public interface TestMapper extends BaseMapper<Test> {
    Test sel(Test t);

    Test seli(Integer id);
    Test seli2(@Param("id")Integer id);

    Test sels(String s);
    Test sels2(@Param("s")String s);
}

對應的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="hx.insist.demo.mapper.TestMapper">

    <select id="sel" parameterType="hx.insist.demo.domain.Test" resultType="hx.insist.demo.domain.Test">
        select * from test
        where 1 = 1
        <if test="id!=null">
            and id = #{id}
        </if>
        <if test="name!=null">
            and name = #{name}
        </if>
        <if test="age!=null">
            and age = #{age}
        </if>
        <if test="num!=null">
            and num = #{num}
        </if>
    </select>

    <select id="seli" parameterType="Integer" resultType="hx.insist.demo.domain.Test">
        select * from test
        where 1 = 1
        <if test="id!=null">
            and id = #{id}
        </if>
    </select>

    <select id="seli2" parameterType="Integer" resultType="hx.insist.demo.domain.Test">
        select * from test
        where 1 = 1
        <if test="id!=null">
            and id = #{id}
        </if>
    </select>

    <select id="sels" resultType="hx.insist.demo.domain.Test">
        select * from test
        where 1 = 1
        <if test="s!=null">
            and name = #{s}
        </if>
    </select>

    <select id="sels2" resultType="hx.insist.demo.domain.Test">
        select * from test
        where 1 = 1
        <if test="s!=null">
            and name = #{s}
        </if>
    </select>
</mapper>

service層:

/**
 * @author: HanXu
 * on 2019/12/18
 * Class description:
 */
@Service
public class TestService {
    @Resource
    private TestMapper testMapper;


    //測試自定義的存在setter方法的對象
    public void selTest(){
         Test t = new Test();
        t.setId(1);

        Test sel = testMapper.sel(t);
        System.out.println(sel);
    }

    //測試Integer
    public void seliTest(){
        Test seli = testMapper.seli(1);
        System.out.println(seli);
    }

    //測試String
    public void selsTst(){
        Test aaa = testMapper.sels("aaa");
        System.out.println(aaa);
    }

    //測試Integer,且寫了@Param
    public void seliTest2(){
        Test seli = testMapper.seli2(1);
        System.out.println(seli);
    }

    //測試String,且寫了@Param
    public void selsTest2(){
        Test test = testMapper.sels2("aaa");
        System.out.println(test);
    }
}

controller層:

@GetMapping("testT")
    public ResponseEntity test(){
        testService.selTest();
        return ResponseEntity.ok().build();
    }

    @GetMapping("testI")
    public ResponseEntity testi(){
        testService.seliTest();
        return ResponseEntity.ok().build();
    }

    @GetMapping("testS")
    public ResponseEntity tests(){
        testService.selsTst();
        return ResponseEntity.ok().build();
    }

    @GetMapping("testI2")
    public ResponseEntity testI2(){
        testService.seliTest2();
        return ResponseEntity.ok().build();
    }

    @GetMapping("testS2")
    public ResponseEntity testS2(){
        testService.selsTest2();
        return ResponseEntity.ok().build();
    }

測試結果:
測試Test seli(Integer id);
在這裏插入圖片描述
在這裏插入圖片描述

測試Test seli2(@Param(“id”)Integer id);
在這裏插入圖片描述
在這裏插入圖片描述
測試Test sels(String s);
在這裏插入圖片描述
在這裏插入圖片描述
測試Test sels2(@Param(“s”)String s);
在這裏插入圖片描述
在這裏插入圖片描述
測試Test sel(Test t);

在這裏插入圖片描述
在這裏插入圖片描述

結論

上述5個測試用例中
分爲三對:

    Test sel(Test t);//5

    Test seli(Integer id);//1
    Test seli2(@Param("id")Integer id);//2

    Test sels(String s);//3
    Test sels2(@Param("s")String s);//4

1和2是一對測試,除了2比1多了一個@Param註解之外其他全部相同,測試結果表示:加了註解的能正確執行,未加註解的不能正確執行。

3和4是一對測試,除了4比3多了一個@Param註解之外其他全部相同,測試結果表示:加了註解的能正確執行,未加註解的不能正確執行。

5和1、3是一對測試,不同之處在於5中的參數是自定義pojo,裏面每個屬性都有setter、getter方法,結果表示:在不加@Param註解的情況下,自定義pojo作爲參數可以正常執行,非自定義pojo(沒有參數的getter方法)作爲參數不能正常執行。

以上基於sql語句中使用了動態sql(存在不確定的語句)

我的猜想:

這跟Mybatis內部實現有關。當你使用動態sql時,#{}去拿你的參數時,默認將參數當成了pojo類型,去取對應屬性的getter方法,而這時如果你的參數不是pojo類型,是一個java定義好的類型,比如參數爲Integer id,String s,使用#{}得到它的值時,Mybatis就會去直接取相應的getter方法,比如反射Integer類,取getId()方法
、反射String類,取getS()方法,但是這些類中並沒有相應的方法,那麼就會報錯:
org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ‘id’ in ‘class java.lang.Integer’
org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ‘s’ in ‘class java.lang.String’

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章