当前位置 : 主页 > 编程语言 > java >

mybatis传参问题parameterType,ResultMap,一级二级缓存

来源:互联网 收集:自由互联 发布时间:2023-12-16
parameterType 传入多个参数 引出问题 /** * 登录 * @param name * @param passworld */ public User login(String name ,String passworld); !--登录--select id="login" resultType="User" select * from tb_user where user_name = #{userna

parameterType

传入多个参数

引出问题

/**
     * 登录
     * @param name
     * @param passworld
     */
    public User login(String name ,String passworld);
<!--登录-->
<select id="login" resultType="User">
    select * from tb_user where user_name = #{username} and passworld = #{passworld}
</select>
@Test
public void testLogin(){
    User u = userMapper.login("jack", "123");
    System.out.println(u);
}

如果传入两个参数或者更多的参数,会发现,多个参数是找不到了,错误如下:


解决方式1

在mapper.xml中使用 0,1这样的序号去,0表示第一个参数,1表示第二个参数。(从0开始数)

<!--登录-->
    <select id="login" resultType="User">
        select * from tb_user where user_name = #{arg0} and passworld = #{arg1}
    </select>

或者 用param1 param2 这个时就是从1开始

<!--登录-->
    <select id="login" resultType="User">
        select * from tb_user where user_name = #{param1} and passworld = #{param2}
    </select>

解决方式2

通过@Param来指定参数名,你写什么就接受什么


#与$区别

1、$字符串拼接,# 参数站位相当于?
2、$不能够防止sql注入,#可以防止sql注入的
3、$要考虑参类型 ,#不用考虑参数类型  
4、$可以替换sql语句任何一个内容,#只能替换参数

#的用法

#不用考虑参数类型

#可以防止sql注入

<!--登录-->
<select id="login" resultType="User">
    <!--使用#-->
    select * from tb_user where user_name = #{name} and passworld = #{passworld}
</select>
/**
 * 登录
 */
public User login(@Param("name") String name ,@Param("passworld") String passworld);
@Test
    public void testLogin(){
        User u = userMapper.login("jack", "123");//#不用考虑参数类型
        User u = userMapper.login("' or '1' = '1", "' or '1' = '1");//#防止sql注入
        System.out.println(u);
    }
  • 根据姓名进行模糊查询
/**
     * 根据姓名进行模糊查询
     * @param name
     * @return
     */
    public List<User> queryByLikeName(String name);
<!--根据姓名进行模糊查询-->
    <select id="queryByLikeName" resultType="User">
        select * from tb_user where user_name like concat('%',#{name},'%')
    </select>
@Test
    public void teseQueryByLikeName(){
        List<User> list = this.userMapper.queryByLikeName("ja");
        for(User user : list){
            System.out.println(user);
        }
    }

$的用法

用于字符串拼接

/**
     * 根据表名来查询
     * @param name
     */
    public List<User> queryByTableName(String name);
<!--根据表名来查询-->
    <select id="queryByTableName" resultType="User">
        select * from ${name}
    </select>
@Test
    public void testqueryByTableName(){
        List<User> list = this.userMapper.queryByTableName("tb_user");
        for(User user : list){
            System.out.println(user);
        }
    }

$ 需要考虑参数类型

$不防止sql注入

<!--登录-->
    <select id="login" resultType="User">
         <!--使用$ 需要考虑参数类型-->
        select * from tb_user where user_name = '${name}' and passworld = '${passworld}'
    </select>
/**
 * 登录
 */
public User login(@Param("name") String name ,@Param("passworld") String passworld);
@Test
    public void testLogin(){
        User u = userMapper.login("jack", "123");//$不用考虑参数类型
        User u = userMapper.login("' or '1' = '1", "' or '1' = '1");//$防止sql注入
        System.out.println(u);
    }

#和$的区别

$可以代替所有#
如果传入的数据,不是sql中的字段的时候,就不能够使用#. 

通常使用#。
选择获取参数的时候,首要选择的# 的方式
(1、可以防止sql注入,2、可以不用考虑数据类型,简化书写,3、sql是参数的话的sql,预编译的sql,速度会块一些)
当#用不了的时候,去选择$例如 ,sql需要改变是表名的情况,就可使用$的方式。

总结:能用# 就不选择$

ResultMap 用法

ResultMap 是Mybatis中最为重要的元素,使用ResultMap 可以解决两大问题:

1、pojo属性名与数据库字段名不一致问题

2、完成高级查询,一对一,一对多, 多对多(后面讲)

代码实现

<!--查询所有映射-->
    <!--
        id:resultMap的标识
        type:映射的类型
        autoMapping:true(默认) 支持 属性名与字段名自动映射  false:只针对resultMap定义的属性映射
    -->
    <resultMap id="userResultMap" type="User" autoMapping="true">
        
        <!--id一般作为主键,它有自己的标签,实现属性名与字段名一一映射-->
        <id column="id" property="id"/>
        
        <!--除了id以外的字段,用result标签实现属性名与字段名一一映射-->
        <result column="user_name" property="userName"/>
        
        <!--如果,属性名与字段一致,可以省略不写-->
        <result column="sex" property="sex"/>

    </resultMap>
    <!--查询所有-->
    <select id="queryAllUser" resultMap="userResultMap">
        select * from tb_user
    </select>

sql片段

作用:把重复的sql语句抽出来来放到sql标签中,然后通<include refid="" />来引入

用法1

<!--抽取sql-->
    <sql id="userColumn">
        id ,user_name ,passworld , sex
    </sql>

    <!--查询所有-->
    <select id="queryAllUser" resultMap="userResultMap">
        select <include refid="userColumn"/> from tb_user
    </select>

如出现以下问题,请参考解决即可:

去掉xml:iBatis3:sql|select|insert|update|delete|statement里面的sql校验即可


用法2

以下用法1抽取的sql只能在本xml中使用,那如何这个抽取的sql其他xml也想使用怎么办呢?用法2就是可以将sql单独抽取到一个文件中,这样其他的xml就可以直接使用

<mapper namespace="abc">

    <!--抽取sql-->
    <sql id="userColumn">
        id ,user_name ,passworld , sex
    </sql>

</mapper>
<!--查询所有-->
    <select id="queryAllUser" resultMap="userResultMap">
        select <include refid="abc.userColumn"/> from tb_user
    </select>
<!--注意别忘了:mybatis-config.xml 引入-->
<mapper resource="UserSQLMapper.xml"/>

动态sql

业务场景:在我们生活中很多业务常常遇到动态搜索的情况,比如搜索民宿,根据位置,价格,面积等等情况动态搜索,参数等信息可以根据我们需求改变,这里就涉及到了我们Mybatis常说的动态SQL。

Mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

Mybatis提供了动态SQL,也就是可以根据用户提供的参数,动态决定查询语句依赖的查询条件或SQL语句的内容。

标签名

解释

if

单条件分支判断

choose, when, otherwise

多条件分支判断

where

处理sql条件接拼where

set

处理sql条件接拼set

foreach

循环操作

trim

处理sql条件拼接

动态sql-if标签

需求1:查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询

/**
        查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询
     */
    public List<User> queryLikeByName(String name);
<!--查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询-->
    <select id="queryLikeByName" resultType="User">
        select * from tb_user where sex = '男'
        <if test="name != null and name !=''">
            and user_name like concat('%',#{name},'%')
        </if>
    </select>
//查询男性用户,如果输入了姓名,姓名进行模糊查找,如果不输入就按男性用户来查询
    @Test
    public void queryLikeByName() {

        List<User> list = this.userMapper.queryLikeByName("ck");
        for(User user : list){
            System.out.println(user);
        }
    }

动态sql-choose, when, otherwise标签

choose,when,otherwise 相当于java中的 if, else if的逻辑

如果其中的一个when 成立,则后的都不执行,如果所有when的都不成立,那么就执行otherwise

也就是谁在前面谁优先

需求2:查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找

/**
     * 查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找
     */
    public List<User> queryByLikeNameAndAge(@Param("name") String name , @Param("age") Integer age);
<!--查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找-->
    <select id="queryByLikeNameAndAge" resultType="User">
        select * from tb_user where sex = '男'

        <choose>
            <when test="name != null and name !=''">
                and user_name like concat('%',#{name},'%')
            </when>
            <when test="age != null and age !=''">
                and age like concat('%',#{age},'%')
            </when>
            <otherwise>
                and id = 12
            </otherwise>
        </choose>

    </select>
//查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找
	@Test
    public void queryByLikeNameAndAge(){
        List<User> list = this.userMapper.queryByLikeNameAndAge("jack", null);
        for(User user : list){
            System.out.println(user);
        }
    }

动态sql-where标签

where标签代替 sql中的where关键字

需求3:查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询

/**
* 查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询
*/
public List<User> queryByAllUserLikeNameAndAge(@Param("name") String name , @Param("age") Integer age);
<!--查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询-->
    <select id="queryByAllUserLikeNameAndAge" resultType="User">
        select * from tb_user
        <where>
            <if test="name != null and name!=''">
                user_name like concat('%',#{name},'%')
            </if>
            <if test="age != null and age!=''">
                and age like concat('%',#{age},'%')
            </if>
        </where>
    </select>
//查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询
    @Test
    public void queryByAllUserLikeNameAndAge(){
        List<User> list = this.userMapper.queryByAllUserLikeNameAndAge("c", 2);
        for(User user : list){
            System.out.println(user);
        }
    }

动态sql-set标签

set标签代替 sql中set关键字

需求4:如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age

/**
* 如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age
*/
public Integer updateByNameOrAge(@Param("name") String name , @Param("age") Integer age , @Param("id") Integer id);
<!--如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age-->
    <update id="updateByNameOrAge">
        update tb_user

        <set>
            <if test="name != null and name!=''">
                user_name =  #{name},
            </if>
            <if test="age != null and age!=''">
                age = #{age}
            </if>
        </set>

        where id = #{id}

    </update>
//如果名字信息不是null,则修改名字, 如果age信息不是null,同时也修改age
    @Test
    public void updateByNameOrAge(){
        Integer integer = this.userMapper.updateByNameOrAge("一燕", 26, 2);
        sqlSession.commit();
        System.out.println(integer);
    }

动态sql-foreach标签

需求5:按照多个id查询用户信息 Select * from t_user where id in(1,2,3)s

/**
     * 按照多个id查询用户信息
     * @param ids
     * @return
     */
    public List<User> queryIds(@Param("ids") int[] ids);
<!--按照多个id查询用户信息-->
    <!--
        collection:接受的是一个集合
        item: 表示遍历的就量
        open: 字符串拼接的开头
        close: 字符串拼接的结尾
        separator: 每一个变量拼接的分隔符
    -->
    <select id="queryIds" resultType="User">
        
        select * from tb_user where id in
        <foreach collection="ids" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>

    </select>
// 按照多个id查询用户信息
    @Test
    public void queryIds(){
        int[] arr ={1,2};
        List<User> list = this.userMapper.queryIds(arr);
        for(User user : list){
            System.out.println(user);
        }
    }

动态sql-trim标签

trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某写后缀,与之对应的属性是prefix和suffix;

可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOver


  • 案例一 prefix用法
/**
 * 查询所有,如果输入姓名,按姓名查询,如果输入性别,就按性别来查询
 */
public List<User> queryNameAndSexTrim(@Param("name") String name , @Param("sex") String sex);
<!--查询所有,如果输入姓名,按姓名查询,如果输入性别,就按性别来查询-->
    <select id="queryNameAndSexTrim" resultType="User">
        select * from tb_user
        /*加前缀,去掉第一个前缀*/
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name !=''">
                and user_name = #{name}
            </if>
            <if test="sex != null and sex !=''">
                and sex = #{sex}
            </if>
        </trim>
    </select>
//查询所有,如果输入姓名,按姓名查询,如果输入性别,就按性别来查询
    @Test
    public void queryNameAndSexTrim(){
        List<User> list = this.userMapper.queryNameAndSexTrim("jack", "男");
        for(User user : list){
            System.out.println(user);
        }
    }
  • 案例二 suffix用法
/**
* 如果名字信息不是null,则修改名字, 如果sex不为null,同时也修改null
*/
public Integer updateByNameOrAgeTrim(@Param("name") String name , @Param("sex") String sex , @Param("id") Integer id);
<!--如果名字信息不是null,则修改名字, 如果sex不为null,同时也修改null-->
    <update id="updateByNameOrAgeTrim">
        update tb_user
        <trim prefix="set" suffixOverrides="," suffix="where id = #{id}">
            <if test="name != null and name !=''">
                user_name = #{name},
            </if>
            <if test="sex != null and sex !=''">
                sex = #{sex},
            </if>
        </trim>
    </update>
//如果名字信息不是null,则修改名字, 如果sex不为null,同时也修改null
@Test
public void updateByNameOrAgeTrim(){
    Integer integer = this.userMapper.updateByNameOrAgeTrim("小江", "女", 2);
    sqlSession.commit();
    System.out.println(integer);

}

缓存

一级缓存

Mybatis的一级缓存的作用域session,当openSession()后,如果执行相同的sql和参数,Mybatis不再执行SQL,而是从缓存中命中并返回;

原理:mybatis执行查询时首先去缓存中命中,如果命中就直接返回,没有命中则执行SQL,从数据库中查

在mybatis中,一级缓存默认是开启的,并且一直无法关闭(我们没法去管理一级缓存

测试一级缓存

@Test
    public void queryById(){

        User user = this.userMapper.queryById(2);//发送sql
        System.out.println(user);

        User user2 = this.userMapper.queryById(2);//不发送sql
        System.out.println(user2);

    }

清空缓存

使用sqlsession.clearCache()清除缓存

@Test
    public void queryById(){

        User user = this.userMapper.queryById(2);//发送sql
        System.out.println(user);

        sqlSession.clearCache();//清空缓存

        User user2 = this.userMapper.queryById(2);//重新发送sql
        System.out.println(user2);

    }

执行update,delete,insert 语句的时候,清空缓存 刷新缓存

@Test
    public void queryById(){

        User user = this.userMapper.queryById(2);//发送sql
        System.out.println(user);

        Integer i = this.userMapper.deleteById(1);//执行删除操作
        sqlSession.commit();
        System.out.println(i);

        User user2 = this.userMapper.queryById(2);//发送sql
        System.out.println(user2);

    }

二级缓存

mybatis 的二级缓存的作用域是一个mapper的namespace ,同一个namespace中查询sql可以从缓存中命中。

二级缓存是跨session

开启二级缓存

需要在当前sql映射文件中开启二缓缓存

<?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="cn.yanqi.mapper.UserMapper">
    
    <!--开启二级缓存-->
    <cache/>

测试二级缓存

@Test
public void queryById(){

    User user = this.userMapper.queryById(2);//发送sql
    System.out.println(user);

    //关闭sqlSession
    sqlSession.close();
	
    SqlSession sqlSession = sqlSessionFactory.openSession();
    userMapper = sqlSession.getMapper(UserMapper.class);

    User user2 = this.userMapper.queryById(2);//不发送sql,表明二级缓存存在
    System.out.println(user2);

}

查看日志输出


关闭二级缓存

<settings>
    <!--开启驼峰匹配-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    
    <!--关闭二级缓存  默认是开启的-->
    <setting name="cacheEnabled" value="false"/>
    
</settings>


【本文由:盐城网页开发公司 http://www.1234xp.com/yancheng.html 复制请保留原URL】
网友评论