1、获取参数的方式

(1).#{} ==> jdbc String sql="select id,username from emp where id = ?"
    (1)会经过JDBC当中PreparedStatement的预编译,会根据不同数据类型来编译成数据库所对应的数据
        id=1
        username='xxx'
    (2)能够有效的防止sql注入(推荐使用)
    特殊用法:
            自带了很多内置参数的属性,通常不会使用
            javaType、jdbcType、mode、numericScale、resultMap、typeHandler
            比如,id可能为null,默认会设置为OTHER(NULL==>OTHER ),但oracle没有other,
             这时,可以写为#{id,javaType=null},想要保留小数点后两位:#{price,numericScale=2}

(2).${} ==> jdbc String sql="select id,username from emp where id =" + id
    (1)不会进行预编译,直接将传进来的数据拼接在sql中
    (2)存在sql注入风险,不推荐使用。
    特殊用法:
            1.调试情况下可以暂时使用
            2.可以实现一些特殊功能(前提:一定保证数据的安全性):
                比如,动态表、动态列、动态SQL
                根据用户选择的列排序

2、参数传递的处理

1.单个参数:selectEmp(Integer id);
     获取方式:
         mybatis不会有什么强制的要求,#{可以输入任何字符来获取参数}
 2.多个参数:Emp selectEmp(Integer id, String username);
     mybatis会将传进来的参数封装成map
     一个参数对应map中两组key和value:
            id ==> {key:arg0,value:id的值},{key:param1,value:id的值}
            username ==> {key:arg1,value:username的值},{key:param2,value:username的值}
     获取方式:
         不使用@Param注解时,可以使用:
                 id =====> #{arg0} 或者 #{param1}
                 username =====> #{arg1} 或者 #{param2}
         除了这种方式(参数名无意义),还有其他方式
         可以使用@Param注解,但是使用注解后arg*的方式就会失效,但是可以使用param*的方式
                 id =====> #{id} 或者 #{param1}
                 username =====> #{username} 或者 #{param2}
 3.javaBean参数
     单个参数:Emp selectEmp(Emp emp);
         获取方式:
             emp.id=====> #{id}
             emp.username=====> #{username }
     多个参数:selectEmp(Integer num, Emp emp);
      获取方式:
         不使用@Param注解时,可以使用:
             num=====> #{arg0}或#{param1}
             emp.id=====> #{arg1.id}或#{param2.id}
             emp.username=====> #{arg1.username}或#{param2.username}
         使用@Param注解时:
             num=====> #{@Param}或#{param1}
             emp.id =====> #{@Param.id} 或者 #{param2.id}
             emp.username =====> #{@Param.username} 或者 #{param2.username}
4.集合或者数组参数:selectEmp(List<String> usernames);
     如果是list,mybatis会自动封装成为map:
      获取方式:username = #{list[0]} or username = #{list[1]}
             {key:"list",value:usernames}
       不使用@Param注解时,要获得:usernames.get(0) =====> #{arg0[0]}
                              usernames.get(0) =====> #{list[0]}
       使用@Param("usernames")注解时,要获得:usernames.get(0) =====> #{usernames[0]}
                                            usernames.get(0) =====> #{param1[0]}

      如果是数组,mybatis会自动封装成为map:
      获取方式:username = #{array[0]} or username = #{array[1]}
             {key:"array",value:usernames}
       不使用@Param注解时,要获得:usernames.get(0) =====> #{arg0[0]}
                              usernames.get(0) =====> #{array[0]}
       使用@Param("usernames")注解时,要获得:usernames.get(0) =====> #{usernames[0]}
                                            usernames.get(0) =====> #{param1[0]}
 4.map参数:和javaBean的参数传递是一样。
     一般情况下:插入或者修改这种参数和pojo属性是全对应的情况,就用javaBean
               请求进来的参数,没有和pojo对应,就用map
               请求进来的参数,没有和pojo对应,但是用频率很高,就用TO(Transfer Object),DTO
               (即单独为这些参数创建一个对应的javaBean出来,是参数传递更规范)

3、返回类型设置

返回类型设置:
    如果返回一行数据,就可以使用pojo或map接收
    如果返回多行数据,就可以使用List<pojo>或List<map>接收,resultType指定list中的泛型类型*****就可以
    基础类型或者包装类型,就直接指定别名就行了

4、自定义结果集

resultType 与 resultMap(Mybatis最强大的特性)不能同时使用
1.声明resultMap自定义结果集(体现出ORM[Object Relational Mapping]淋漓尽致)
  id 唯一标识,需要<select 上的resultMap进行对应
  type 需要映射的pojo对象,可以设设置别名(前提是配置了别名<TypeAlias>)
  autoMapping 自动映射(默认值为true),只要数据库字段与JavaBean属性名遵循映射规则就可以自动映射
    但是不建议,哪怕属性名与字段名字一致,也要显式的写入
  extends 如果多个resultMap有重复的映射,可以声明父resultMap,将公共映射提取出来,可以减少子resultMap映射的冗余
  主键用<id>元素,其他字段都用<result>元素
2.
<resultMap id="common_map" type="emp">
        <!--主键必须使用<id ,对底层的存储有性能作用
            column 映射的数据库字段名
            property 映射的pojo属性名
        -->
        <id column="id" property="id" />
        <result column="username" property="username" />
    </resultMap>
    <resultMap id="emp_map1" type="emp" extends="common_emp">
        <result column="createdate" property="date" />
    </resultMap>

5、Select 元素的属性

属性 描述
id 在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType  将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
resultType 期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap  对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
flushCache 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache   将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout    这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
fetchSize  这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。
statementType  可选 STATEMENT,PREPARED 或 CALLABLE(存储过程)。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetType  FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。
databaseId 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
resultSets 这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。

6.1、EmpMapper.java

package cn.qqa.mapper;

import cn.qqa.pojo.Emp;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 注意
 * xxxMapper.xml文件中,同一个命名空间只能有一个唯一的id,
 * 所以在接口中也只能有唯一一个方法名,虽然java中可以函数重载,但是mybatis不支持
 */
public interface EmpMapper {


/*
    单个参数,#{随便输入}
    //查询
    Emp selectEmp(Integer id);
*/
/*
    多个参数
    不使用@Param注解时,可以使用:
    id =====> #{arg0} 或者 #{param1}
    username =====> #{arg1} 或者 #{param2}
    使用@Param注解,但是使用注解后arg*的方式就会失效,但是可以使用param*的方式
    id =====> #{id} 或者 #{param1}
    username =====> #{username} 或者 #{param2}
    Emp selectEmp(@Param("id") Integer id,@Param("username") String username);
*/
/*
    3.javaBean参数
    单个参数:Emp selectEmp(Emp emp);
    获取方式:
    emp.id=====> #{id}
    emp.username=====> #{username }
    多个参数:selectEmp(Integer num, Emp emp);
    获取方式:
    不使用@Param注解时,可以使用:
    num=====> #{arg0}或#{param1}
    emp.id=====> #{arg1.id}或#{param2.id}
    emp.username=====> #{arg1.username}或#{param2.username}
    使用@Param注解时:
    num=====> #{@Param}或#{param1}
    emp.id =====> #{@Param.id} 或者 #{param2.id}
    emp.username =====> #{@Param.username} 或者 #{param2.username}
    Emp selectEmp(Integer num, Emp emp);*/

/*
            如果是list,mybatis会自动封装成为map:
                获取方式:username = #{list[0]} or username = #{list[1]}
                    {key:"list",value:usernames}
                要获得usernames.get(0) =====> #{list[0]}
    List<Emp>  selectEmp(List<String> usernames);
*/
    Emp  selectEmp(Integer id);

/*
    Integer select1(String username,@Param("id") Integer id);

    Integer select2(@Param("beginDate") String beginDate, String endDate,
                    Emp emp);

    Integer select3(List<Integer> ids,String [] usernames,
                    @Param("beginDate") String beginDate, String endDate);
*/



}

6.2、EmpMapper.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="cn.qqa.mapper.EmpMapper">

    <!--
        获取参数的方式
        1.#{} ==> jdbc String sql="select id,username from emp where id = ?"
            (1)会经过JDBC当中PreparedStatement的预编译,会根据不同数据类型来编译成数据库所对应的数据
                id=1
                username='xxx'
            (2)能够有效的防止sql注入(推荐使用)
            特殊用法:
                    自带了很多内置参数的属性,通常不会使用
                    javaType、jdbcType、mode、numericScale、resultMap、typeHandler
                    比如,id可能为null,默认会设置为OTHER(NULL==>OTHER ),但oracle没有other,
                     这时,可以写为#{id,javaType=null},想要保留小数点后两位:#{price,numericScale=2}

        2.${} ==> jdbc String sql="select id,username from emp where id =" + id
            (1)不会进行预编译,直接将传进来的数据拼接在sql中
            (2)存在sql注入风险,不推荐使用。
            特殊用法:
                    1.调试情况下可以暂时使用
                    2.可以实现一些特殊功能(前提:一定保证数据的安全性):
                        比如,动态表、动态列、动态SQL
                        根据用户选择的列排序
    -->

    <!--
        参数传递的处理
        1.单个参数:selectEmp(Integer id);
            获取方式:
                mybatis不会有什么强制的要求,#{可以输入任何字符来获取参数}
        2.多个参数:Emp selectEmp(Integer id, String username);
            mybatis会将传进来的参数封装成map
            一个参数对应map中两组key和value:
                   id ==> {key:arg0,value:id的值},{key:param1,value:id的值}
                   username ==> {key:arg1,value:username的值},{key:param2,value:username的值}
            获取方式:
                不使用@Param注解时,可以使用:
                        id =====> #{arg0} 或者 #{param1}
                        username =====> #{arg1} 或者 #{param2}
                除了这种方式(参数名无意义),还有其他方式
                可以使用@Param注解,但是使用注解后arg*的方式就会失效,但是可以使用param*的方式
                        id =====> #{id} 或者 #{param1}
                        username =====> #{username} 或者 #{param2}
        3.javaBean参数
            单个参数:Emp selectEmp(Emp emp);
                获取方式:
                    emp.id=====> #{id}
                    emp.username=====> #{username }
            多个参数:selectEmp(Integer num, Emp emp);
             获取方式:
                不使用@Param注解时,可以使用:
                    num=====> #{arg0}或#{param1}
                    emp.id=====> #{arg1.id}或#{param2.id}
                    emp.username=====> #{arg1.username}或#{param2.username}
                使用@Param注解时:
                    num=====> #{@Param}或#{param1}
                    emp.id =====> #{@Param.id} 或者 #{param2.id}
                    emp.username =====> #{@Param.username} 或者 #{param2.username}
       4.集合或者数组参数:selectEmp(List<String> usernames);
            如果是list,mybatis会自动封装成为map:
             获取方式:username = #{list[0]} or username = #{list[1]}
                    {key:"list",value:usernames}
              不使用@Param注解时,要获得:usernames.get(0) =====> #{arg0[0]}
                                     usernames.get(0) =====> #{list[0]}
              使用@Param("usernames")注解时,要获得:usernames.get(0) =====> #{usernames[0]}
                                                   usernames.get(0) =====> #{param1[0]}

             如果是数组,mybatis会自动封装成为map:
             获取方式:username = #{array[0]} or username = #{array[1]}
                    {key:"array",value:usernames}
              不使用@Param注解时,要获得:usernames.get(0) =====> #{arg0[0]}
                                     usernames.get(0) =====> #{array[0]}
              使用@Param("usernames")注解时,要获得:usernames.get(0) =====> #{usernames[0]}
                                                   usernames.get(0) =====> #{param1[0]}
        4.map参数:和javaBean的参数传递是一样。
            一般情况下:插入或者修改这种参数和pojo属性是全对应的情况,就用javaBean
                      请求进来的参数,没有和pojo对应,就用map
                      请求进来的参数,没有和pojo对应,但是用频率很高,就用TO(Transfer Object),DTO
                      (即单独为这些参数创建一个对应的javaBean出来,是参数传递更规范)
    -->

    <!--select1(String username,@Param("id") Integer id);-->
<!--    <select id="select1" resultType="int">
        SELECT id,username FROM EMP WHERE username = #{param1} and id = #{id}
    </select>-->

    <!--
        Integer select2(@Param("beginDate") String beginDate, String endDate,
                    Emp emp);
    -->
<!--    <select id="select2" resultType="int">
        SELECT id,username FROM EMP WHERE createdate = #{beginDate} and endDate = #{param2}
            and id = #{param3.id} and username = #{param3.username}
    </select>-->

    <!--
        Integer select3(List<Integer> ids,String [] usernames,
                    @Param("beginDate") String beginDate, String endDate);

    -->
    <select id="select3" resultType="int">
        SELECT count(*) FROM EMP WHERE id = #{param1[0]} or id = #{param1[1]}
        or username = #{param2[0]} or username = #{param2[1]}
        or createdate = #{beginDate} or endDate = #{param4}
    </select>


    <!--
        返回类型设置:
            如果返回一行数据,就可以使用pojo或map接收
            如果返回多行数据,就可以使用List<pojo>或List<map>接收,resultType指定list中的泛型类型*****就可以
            基础类型或者包装类型,就直接指定别名就行了

    -->

    <!--
        resultType 与 resultMap(Mybatis最强大的特性)不能同时使用
        1.声明resultMap自定义结果集(体现出ORM[Object Relation Mapping]淋漓尽致)
          id 唯一标识,需要<select 上的resultMap进行对应
          type 需要映射的pojo对象,可以设设置别名(前提是配置了别名)
          autoMapping 自动映射(默认值为true),只要数据库字段与JavaBean属性名遵循映射规则就可以自动映射
            但是不建议,哪怕属性名与字段名字一致,也要显式的写入
          extends 如果多个resultMap有重复的映射,可以声明父resultMap,将公共映射提取出来,可以减少子resultMap映射的冗余
          主键用<id>元素,其他字段都用<result>元素

    -->
    <resultMap id="common_map" type="emp">
        <!--主键必须使用<id ,对底层的存储有性能作用
            column 映射的数据库字段名
            property 映射的pojo属性名
        -->
        <id column="id" property="id" />
        <result column="username" property="username" />
    </resultMap>
    <resultMap id="emp_map1" type="emp" extends="common_emp">
        <result column="createdate" property="date" />
    </resultMap>
    <resultMap id="emp_map"     type="emp">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="createdate" property="date" />
    </resultMap>
    <!--使用resultMap关联自定义结果集的id-->
    <!--根据id查询Emp对应实体(数据库字段)-->
    <select id="selectEmp"  resultMap="emp_map">
        SELECT id,username,createdate FROM EMP WHERE id = #{id}
    </select>

<!--
Select 元素的属性
属性	描述
id	在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType	将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap	用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。
resultType	期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap	对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
flushCache	将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache	将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout	这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
fetchSize	这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。
statementType	可选 STATEMENT,PREPARED 或 CALLABLE(存储过程)。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetType	FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。
databaseId	如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
resultSets	这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。


-->
</mapper>

6.3、MybatisHomeworkTest.java

package cn.qqa.tests;

import cn.qqa.mapper.EmpMapper;
import cn.qqa.pojo.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

/**
 * 日志配置
 * 1.导入pom依赖
 * 2.添加logback配置文件
 * 3.在某个类下加入声明
 */
public class MybatisHomeworkTest {
    Logger logger = LoggerFactory.getLogger(this.getClass());
    SqlSessionFactory sqlSessionFactory;
    @Before
    public void before(){
        //从XML中构建SqlSeesionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        }catch (IOException e){
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }


/*    @Test
    public void test01() throws IOException, SQLException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        try{
            String[] usernames =new String[]{"秦清澳","汪星源"};
            List<Emp> emps = mapper.selectEmp(usernames);
            System.out.println(emps);
        }catch (Exception ex){

            System.out.println("查询失败!");
        }
        sqlSession.commit();
        sqlSession.close();
    }*/

    /**
     *select1(String username,@Param("id") Integer id);
     */
/*    @Test
    public void test02() throws IOException, SQLException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        try{
            String[] usernames =new String[]{"秦清澳","汪星源"};
            Integer res= mapper.select1("qqa",1);
            System.out.println(res);
        }catch (Exception ex){
            ex.printStackTrace();
            System.out.println("查询失败!");
        }
        sqlSession.commit();
        sqlSession.close();
    }*/

    /**
     Integer select2(@Param("beginDate") String beginDate, String endDate,
     Emp emp);
     */
/*    @Test
    public void test03() throws IOException, SQLException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        try{
            String[] usernames =new String[]{"秦清澳","汪星源"};
            Emp emp = new Emp(1, "qqa");
            Integer res= mapper.select2("11:01","12:01",emp);
            System.out.println(res);
        }catch (Exception ex){
            ex.printStackTrace();
            System.out.println("查询失败!");
        }
        sqlSession.commit();
        sqlSession.close();
    }*/
/*    Integer select3(List<Integer> ids, String [] usernames,
                    @Param("beginDate") String beginDate, String endDate);*/
 /*   @Test
    public void test04() throws IOException, SQLException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        try{
            List<Integer> ids = Arrays.asList(1,5);
            String[] usernames =new String[]{"秦清澳","汪星源"};
            Emp emp = new Emp(1, "qqa");
            Integer res= mapper.select3(ids, usernames,"11:01","12:01");
            System.out.println(res);
        }catch (Exception ex){
            ex.printStackTrace();
            System.out.println("查询失败!");
        }
        sqlSession.commit();
        sqlSession.close();
    }*/
}