前提提要


对于mybatis框架的使用,按照上次介绍的,我们配置的映射文件中,通过namespace将映射文件和接口关联起来了。

具体方法通过id精确的对应。然后,方法对应的具体数据操作,在mapper文件中的<insert><select>.... 书写具体的SQL语句来进行实现。

但是,对于一些需要传输数据的行为,如条件查询,插入操作等等,都需要将用户调用接口的实际参数数据,落实到具体的mapper文件中的各个方法中。

问题来了?

给接口的实际参数,mapper实际操作如何取对应的数据, 数据是以什么方式传递给mapper中各标签实现数据的CRUD操作的呢?


一,IDEA中设置各种配置文件的模板🍍

这节内容主要就是平时开发过程中的技巧性操作。

1. 设置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>

    <properties resource="jdbc.properties"></properties>

    <typeAliases>
        <package name=""></package>
    </typeAliases>

    <!--设置连接数据库的环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url"
                          value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <package name=""/>
    </mappers>
</configuration>

IDEA中添加mybatis-config.xml文件模板的具体操作:
在这里插入图片描述
最后的效果如图所示,新建完上述模板之后,就可以按照上述你创建的模板创建一个mybatis-config.xml文件。
在这里插入图片描述

2. 设置 **mapper.xml映射文件模板🖼

和上述mybatis-confg.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="">

</mapper>

具体的操作和设置mybatis-config.xml操作是一样的。

在这里插入图片描述

二,获取参数的两种方式🍋

✍在谈将调用接口的实际参数传给mapper中各个标签实际操作是什么样之前,我们先看看mapper中获取参数的两种方式,我们知道JDBC中有两种设置参数的方式:

  1. 通过参数预处理的方式 2. 通过拼接SQL的方式
    @Test
    public void testJDBC() throws SQLException, ClassNotFoundException {
        String username = "cherry";
        Class.forName("");
        Connection connection = DriverManager.getConnection("", "", "");
        // 1. 字符串拼接 ->获得预编译对象 -》sql注入问题
        PreparedStatement preparedStatement = connection.prepareStatement("select * from t_user where username = '" + username + "'");

        // 2. 占位符
        PreparedStatement ps2 = connection.prepareStatement("select * from t_user where username = ?");
        ps2.setString(1, username);
    }

对应于MyBatis中,我们也有这两种方式:1. 字符串拼接 2. 占位符

🎾MyBatis获取参数值的两种方式:${}#{},就和JDBC中的两种方式一脉相承。

  • ${}的本质就是字符串拼接
  • #{}的本质就是占位符赋值

${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号(尽量使用这一种)。🤬

两种方式的具体区别可以查看博主的另外一篇文章:
Mybatis参数绑定中的#{ }和${ }区别剖析

三,MyBatis获取参数值的五种情况🚐

通过了上述说明了Mybatis中两种获取基本方式的区别。下面通过给接口床传递实参不同的形式来划分为一下五种情况进行一一的说明。

3.1 单个字面量类型的参数

也就是如果调用的形式是:

getUserById(1) 

🏟若mapper接口中的方法参数为单个的字面量类。此时可以使用${}#{}以任意的名称获取参数的值,注意${}需要手动加单引号。
如下所示:

public interface ParameterMapper {
    /**
     * 单个的字面量类型:
     * 根据用户名查询用户信息
     */
    User getUserByUserName(String username);
}

在对应的配置类中进行配置,按照上述的方式,都可以进行配置,如下:

🆘Notice:使用#{},里面内容可以随便写,都是传进来的username的值。

方式一:

<!--    User getUserByUserName(String username);-->
<!--    使用#{},里面内容可以随便写,都是传进来的username的值-->
    <select id="getUserByUserName" resultType="User">
       select * from t_user where username = #{username}
    </select>

方式二:

<!--    User getUserByUserName(String username);-->
    <select id="getUserByUserName" resultType="User">
        <!-- 
       select * from t_user where username = ${username}
          如果使用这种方式,得到的sql语句是:
          Preparing: select * from t_user where username = RUOYI
          而其中username的值‘RUOYI’没有单引号,语句不正确,会报错。
          因此要手动添加单引号
       -->
        select * from t_user where username = '${username}'
    </select>

测试类:

    /**
     * MyBatis获取参数值的各种情况:
     * 情况1: mapper接口方法的参数为单个字面量的参数
     * 可以通过${} #{}以任意的字符串获得参数值,但需要注意${}的单引号问题
     */
    @Test
    public void testgetUserByUserName(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
        User user = mapper.getUserByUserName("");
        System.out.println(user);
    }

3.2 多个字面量类型的参数

若在mapper接口的方法中有多个参数的时候,我们MyBatis的操作是会自动的将这些参数放到一个Map集合中。通过以arg0, arg1, arg2... argn,以参数值为值。还有一种就是通过param1, param2...,以参数为值。
📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧📧
因此,只要通过#{}或者是${}访问map集合中的键就可以获取到对应的值。但是需要注意的是${}需要手动加上单引号。

public interface ParameterMapper {
    /**
     * 验证登录
     */
    User checkLogin(String username, String password);
}

对应在mapper映射文件中:

<!--    User checkLogin(String username, String password);-->
    <select id="checkLogin" resultType="User">
        <!--
        写:select * from t_user where username = #{username} and password = #{password}
        会报错:Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
        因为sql语句没有解析成功-->

        <!--以map集合形式存储,arg0->param0, arg1->param1,这时直接用键arg访问就好了,用param访问也行。

		以下两种方式选一个:-->
        select * from t_user where username = #{arg0} and password = #{arg1}
        select * from t_user where username = '${param1}' and password = '${param2}'
    </select>

测试类:

    /**
     * 情况2:mapper接口方法的参数为多个时
     * 此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
     * a》以arg0,arg1。。为键,参数为值
     * b》以param0,param1。。为键,参数位置
     * 因此只需要通过#{}和${}以键的方式访问值即可,但需要注意${}的单引号问题
     */
    @Test
    public void testCheckLogin(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
        User user = mapper.checkLogin("fangshaolei","123456");
        System.out.println(user);
    }

Notice: 写:select * from t_user where username = #{username} and password = #{password}

会报错:Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2] 因为sql语句没有解析成功

3.3 Map集合类型的参数

我们大概有了一些思路,基本上对于所有的参数。Mybatis的操作都是先将所有的参数都封装到一个map中,然后在mapper中使用#{}或者是${}来进行取。

如果mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,也就是我们不在通过mybatis来进行创建参数,而是手动的自己传过去一个map

🌼所以,将这些数据放在map中只需要通过${}#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号.

public interface ParameterMapper {
	/**
     * 验证登录
     */
    User checkLoginByMap(Map<String, Object> map);
}

在对应的map中进行取用的操作。

<!--    User checkLoginByMap(Map<String, Object> map);-->
    <select id="checkLoginByMap" resultType="User">
        select * from t_user where username = #{username} and password = #{password}
    </select>

测试类:

    /**
     * 情况3:若mapper接口方法的参数有多个时,可以手动将这些参数放在一个map中存储
     * 只需要通过#{} ${}以键的方式访问值即可,但是需要注意${}的单引号问题
     */
    @Test
    public void testCheckLoginByMap(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);

        Map<String, Object> map = new HashMap<>();
        map.put("username","RUOYI");
        map.put("password","123456");

        User user = mapper.checkLoginByMap(map);
        System.out.println(user);
    }

🆘Notice:但是需要注意的是,对于自己封装的map的形式,在使用两种方式进行取用的时候,需要指定在map中的键,也就是我们自己存在map数据中的键。

3.4 实体类参数

🚦如果mapper接口中的方法参数是实体类对象的时候,此时可以使用 #{}${},通过访问实体类对象中的属性名获取属性值,同样需要注意的是:${}需要手动加上单引号。

其实,实体类对象参数,在mybatis中会被封装成map对象的形式。
Mapper对应的接口:

public interface ParameterMapper {
    /**
     * 添加用户信息
     */
    int insertUser(User user);
}

Mapper.xml文件中的配置:

<!--        int insertUser(User user);-->
<!--    找到相对应的get方法,如username->找getUsername(),看get/set方法-->
    <insert id="insertUser">
        insert into t_user values(null, #{username}, #{password}, #{age}, #{gender}, #{email})
    </insert>

测试类:

    /**
     * 情况4:mapper接口方法的参数是实体类类型的参数(web从control层传过来的)
     * 只需要通过#{} ${}以属性的方式访问属性值即可,但是需要注意${}的单引号问题
     */
    @Test
    public void testInsertUser(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);

        User user = new User(null, "fangshaolei", "123456", 66, "m", "sl.fang@gmail.com");
        mapper.insertUser(user);
    }

Notice:同样需要注意的是,#{}中的参数名称不能随意的写,要和属性名称一致。

3.5 使用@Param标识参数

🚿通过上述的四种方法,我们知道,除了只有一个字面量参数之外。其他的参数通过#{}或者是${}取用的值都需要正确的给定Mybatis内部map的键。

如果是多个字面量,按照Mybatis内部默认的键来进行取用。如果传过来的参数是自己定义的Map或者是实体类对象的形式。则在取用的时候,指定参数名称和自定义Map的键一致和如果参数是实体类对象,则需要和对象的属性名一致。
😵
但是,我们能够自定义Mybatis内部已经封装好的Mapkey,从而通过#{}或者是${}的形式,利用我们自定义的key来进行取用呢?

这就需要通过@Param来实现。
🚣‍♂️可以通过@Param注解标识mapper接口中的方法参数。此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;
param1,param2...为键,以参数为值;
只需要通过${}#{}访问map集合的键就可以获取相对应的值, 注意${}需要手动加单引号。

public interface ParameterMapper {
    /**
     * 验证登录 (使用@Param)
     */
    User checkLoginByParam(@Param("username") String username, @Param("password") String password);
}

对应的mapper.xml配置:

<!--    以@Param的值为键,参数为值; 或以"param1"/"param2"为键,参数为值-->
<!--    User checkLoginByParam(@Param("username") String username, @Param("password") String password);-->
    <select id="checkLoginByParam" resultType="User">
        select * from t_user where username = #{username} and password = #{password}
    </select>

测试类:

    /**
     * 情况5:使用@Param注解来命名参数
     * 此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
     * a》以@Param的值为键,参数为值; @Param(value = "xxx")
     * b》以param0,param1...为键,参数为值
     */
    @Test
    public void testCheckLoginByParam(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
        User user = mapper.checkLoginByParam("fangshaolei","123456");
        System.out.println(user);
    }

而对于参数传递的源码分析,可以看博主的另外一篇博文:👩‍🏫

Mybatis参数传递介绍与源码分析

四,总结🌼

我们还是把第一篇博文的图片拿出来分析:
在这里插入图片描述

🥪我们知道,对于参数传递的总体位置是在:在mybatis中是如何将给接口的参数,被mapper.xml进行接收的。
博文中,分开了五种情况来进行介绍。
在这里插入图片描述


🎦对于上述的几种情况:对于开发中,我们常用的思路就是,无论你是单字面量还是多字面量。无论是对象,还是map
我们一律通过两种方式来使用:

  • 所有的非实体类,非map。我们都打上一个@Param来指定取用的参数名称。
  • 如果是实体类和map,则直接使用key或者是对象的属性名。

所以,我们只需要记住两种情况就可以。


推荐阅读 | 参考博文
https://blog.csdn.net/bdqx_007/article/details/94836637

https://www.cnblogs.com/mingyue1818/p/3714162.html

https://baijiahao.baidu.com/s?id=1695300185179901379&wfr=spider&for=pc

https://blog.51cto.com/legend2011/1030804


🌈🌈🌈文章还有许多不足的地方,欢迎指正。💌

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐