MyBatis有参查询及动态查询

上一篇博客中写了如何实现最简单的selectAll()查询所有的方法。下面继续说怎么实现有参查询和动态查询。

  在说之前先说一下,数据库表中的字段名称和实体类中的属性名称不一样,则不能自动封装,就比如customer_id 和customerId。

  解决办法:1、起别名:select customer_id as customerId.    缺点:每次查询时都需要起一次别名。解决办法:用sql片段。

<!-- 一   sql片段-->
    <sql id="brand_column">
            id ,brand_name as brandName
        </sql>
    <!--    引用sql片段时 select<include refid="brand_column"/>导入 -->

sql片段缺点:不灵活。

                  2、resultMap:resultMap (1).定义<resultMap>标签;(2).在<select>标签中,使用resultMap属性代替resultType属性。

<resultMap id="brandResultMap" type="org.example.pojo.brand">
        <result column="customer_id" property="id"/>
<!--  id:完成主键字段的映射;result :完成一般字段的映射。
              column为表中的列名,property为实现类中的属性名-->
    </resultMap>

设置好resultMap后,就可以直接在<select>标签引用:

 <select id="selectAll" resultMap="brandResultMap">
        select *
        from sql_store.customers
    </select>

下面开始说带参查询:

    1、根据id查询

          先在接口方法中定义好接口

brand selectById(int id);

定义好方法后,selectById下面会有红波浪线报错,这是因为在Mapper.xml文件中找不到对应的方法,我们需要在Mapper.xml文件中声明对应的方法。我们不用手动跳转到xml文件界面然后手动输入方法,我们可以将光标停留在该方法中,然后按着 option键在按俩次回车就可以了。(我的是苹果电脑)

按一次回车后出现下面的选项,然后在按一次回车就可以自动在xml文件中生成对应的方法了。

生成对应的<select>标签后在补充完整就好了:

<select id="selectById" parameterType="int" resultMap="brandResultMap">
        select*
        from sql_store.customers
        where customer_id =#{id};
    </select>

参数占位符:1、#{}:会将其替换成?,为了防止sql注入。
2、${}:拼sql,会存在sql注入问题。
3、使用时机
参数传递的时候:#{}
表名或列名不固定的时候用${},灵活引用,但因为用${}就会存在sql注入,所以不常用。
参数类型:parameterType可以省略不写
特殊符号:就比如sql语句中where后跟的条件符号>号没问题,可<号就会报错
                 1、转义字符:&lt;就是<号的意思。
                  2、CDATA区:<![CDATA[
                  <
                  ]]> ,把想用的符号写在中间。

 接下来是多条件查询

         1、散装查询,传入多个参数查询:

List<brand>selectByCondition(@Param("id")int id,@Param("city")String city,@Param("firstName")String first_name);

测试方法:

@Test
    public void selectByCondition() throws IOException {
        //接收参数
        int id=1;
        String city="a";
       String firstName="B";

        //手动处理参数
        city="%"+city+"%";
        firstName="%"+firstName+"%";


        //1.获取SqlSessionFactory。
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3.获取Mapper接口的代理对象
        brandMapper brandMapper = sqlSession.getMapper(brandMapper.class);
        //4.执行方法
        List<brand> brands = brandMapper.selectByCondition(id, city, first_name);
        System.out.println(brands);

        //5.释放资源
        sqlSession.close();
    }

 

使用@Param(“sql参数占位符名称”)

       2、对象参数:对象属性名称要与参数占位符名称一致; 

List<brand>selectByCondition(brand brand);

将实体类作为参数传入。

测试方法:

@Test
    public void selectByCondition() throws IOException {
        //接收参数
        int id=1;
        String city="a";
       String firstName="B";

        //手动处理参数
        city="%"+city+"%";
        firstName="%"+firstName+"%";



        //封装对象
       brand brand=new brand();
       brand.setId(id);
       brand.setCity(city);
       brand.setFirstName(firstName);

        //1.获取SqlSessionFactory。
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3.获取Mapper接口的代理对象
        brandMapper brandMapper = sqlSession.getMapper(brandMapper.class);
        //4.执行方法
        List<org.example.pojo.brand> brands = 
      brandMapper.selectByCondition(brand);
        System.out.println(brands);

        //5.释放资源
        sqlSession.close();
    }

   3、map集合对象:

List<brand> selectByCondition(Map map);

 测试方法:

@Test
    public void selectByCondition() throws IOException {
        //接收参数
        int id=1;
        String city="a";
       String firstName="B";

        //手动处理参数
        city="%"+city+"%";
        firstName="%"+firstName+"%";

        Map map=new HashMap();
        map.put("customer_id",id);
        map.put("city",city);
        map.put("first_name",firstName);

        //1.获取SqlSessionFactory。
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3.获取Mapper接口的代理对象
        brandMapper brandMapper = sqlSession.getMapper(brandMapper.class);
        //4.执行方法
        List<brand> brands = brandMapper.selectByCondition(map);
        System.out.println(brands);

        //5.释放资源
        sqlSession.close();
    }

Mapper.xml文件中这样写<select>标签,like是模糊查询,比如你city输入一个字母c,那么 数据库中city列中所有包含字母c的都会被查到。

<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from sql_store.customers
        where customer_id=#{id}
        and city like #{city}
        and first_name like #{firstName}
    </select>

动态多条件查询:客户可能只传入1个参数,可能传入多个参数,而且我们是不知道传入多少个参数的。

   这时我们可以用if标签来判断:

<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from sql_store.customers
        where 
        <if test="customer_id!=null">
            customer_id=#{id}
        </if>
         <if test="city!=null and city!=''">
         and city like #{city}
    </if>
        <if test="first_name!=null and first_name!=''">
         and first_name like #{firstName}
    </if>
    </select>

问题:如果第一个if不存在,那么查询的sql语句where条件中会多一个and,sql语句会报错。
解决:1、在第一个if前加上and,然后在最开头加上一个恒等式,比如1=1

<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from sql_store.customers
        where 1=1 
            <if test="customer_id!=null">
                and customer_id=#{id}
            </if>
            <if test="city!=null and city!=''">
                and city like #{city}
            </if>
            <if test="firstName!=null and firstName!=''">
                and first_name like #{firstName}
            </if>
    </select>


2、mybatis提供了<where>标签来替换where关键字

<select id="selectByCondition" resultMap="brandResultMap">
        select *
        from sql_store.customers
        <where>
            <if test="customer_id!=null">
                and customer_id=#{id}
            </if>
            <if test="city!=null and city!=''">
                and city like #{city}
            </if>
            <if test="firstName!=null and firstName!=''">
                and first_name like #{firstName}
            </if>
        </where>
    </select>

以上就是动态的多条件查询。

接下来是动态的单条件查询,查询时客户可能一个条件也不选,这样sql语句中where后就什么也没有了,sql语句会报错。

             解决:1、<choose>标签中的otherwise标签     2、<where>标签与choose标签连用

    choose标签:choose标签就相当于switch,其中的when标签就相当于case,otherwise标签相当于default。

 <select id="selectByConditionSingle" resultMap="brandResultMap">
         select *
         from sql_store.customers
         where
         <choose>
             <when test="id!=null ">
                 customer_id= #{id}
             </when>
             <when test="city!=null and city!=''">
                 city like #{city}
             </when>
             <when test="firstName!=null and firstName!=''">
                 first_name like #{firstName}
             </when>
             <otherwise>
                 1=1
             </otherwise>
         </choose>
     </select>

   where与choose标签连用:这样写就不用写otherwise标签了。

 <select id="selectByConditionSingle" resultMap="brandResultMap">
        select *
        from sql_store.customers
        <where>
            <choose>
                <when test="id!=null ">
                    customer_id= #{id}
                </when>
                <when test="city!=null and city!=''">
                    city like #{city}
                </when>
                <when test="firstName!=null and firstName!=''">
                    first_name like #{firstName}
                </when>
            </choose>
        </where>
    </select>

 

以上就是关于查询的所有东东了。

### 解决 MyBatis 中使用问号作为入的问题 在 MyBatis 中,`#{}` 是 SQL 数占位符,会被替换为 `?` 并通过 PreparedStatement 设置数值。如果 SQL 语句中直接包含问号,则可能导致预编译后的 SQL 出现多个未定义的 `?` 占位符,从而引发异常。 为了正确处理带有问号的数传递,可以采用以下几种方法: #### 方法一:使用自定义转义字符 可以通过配置 MyBatis 的属性来指定不同的转义字符替代默认的问号。这可以在 MyBatis 配置文件中完成: ```xml <configuration> <settings> <!-- 使用 @ 替代 ? --> <setting name="mapUnderscoreToCamelCase" value="false"/> <setting name="useStatement" value="true"/> <setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver"/> <setting name="jdbcTypeForNull" value="NULL"/> <setting name="callSettersOnNulls" value="true"/> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="autoMappingBehavior" value="PARTIAL"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="safeRowBoundsEnabled" value="false"/> <setting name="localCacheScope" value="SESSION"/> <setting name="statementTimeout" value="0"/> <setting name="transactionIsolationLevel" value="READ_COMMITTED"/> <setting name="skipErrors" value="none"/> <setting name="logPrefix" value=""/> <setting name="logImpl" value="SLF4J"/> <setting name="proxyFactory" value="CGLIB"/> <setting name="vfsImpl" value=""/> <setting name="useActualParamName" value="true"/> <setting name="returnInstanceForEmptyRow" value="false"/> <setting name="maxBuilderNestedDepth" value="32"/> <setting name="shrinkWhitespacesInSql" value="false"/> <setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.thymeleaf.ThymeLeafLanguageDriver"/> <setting name="expressionInterpolationEnabled" value="false"/> <setting name="scriptPattern" value="(\\$\\{|#\\{)[^}]+}\\}|@[^ ]+ "/> <!-- 自定义正则表达式匹配模式 --> </settings> </configuration> ``` 这种方法适用于全局修改,默认情况下不推荐这样做,因为可能影响其他部分的功能正常运行。 #### 方法二:利用 CDATA 区域包裹 SQL 片段 对于特定的 SQL 查询,可以直接将整个 SQL 表达式放入 `<![CDATA[]]>` 标签内,这样就可以保留原始字符串而不被解析器干扰。 ```xml <select id="selectAll" resultMap="user"> <![CDATA[ SELECT * FROM table WHERE 1=1 AND name LIKE '%?%' ]]> </select> ``` 这种方式简单有效,但仅限于静态 SQL 或者不需要动态构建的情况。 #### 方法三:调整 SQL 编写方式 最常用的方法是在编写 SQL 时避开直写的问号符号,改用更安全的方式表示变量或通配符。例如,当需要模糊查询时,应该使用 `%${value}%` 形式的拼接而不是硬编码问号。 ```sql WHERE column_name LIKE CONCAT('%', #{searchTerm}, '%') ``` 此法不仅解决了问号冲突问题,还提高了代码的安全性和可读性。 以上三种方案可以根据实际需求灵活选用,通常建议优先考虑第三种做法——即优化 SQL 写作习惯以规避潜在的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值