您的位置:首页 > 数据库

第二章Mybatis的SQL映射文件和ResultMap

2018-01-25 21:49 489 查看
一、SQL映射文件

1.CRUD

Mybatis允许定义以下类型的返回值:Integer、Long、Boolean、void

//mybatis引入将Integer、Long、Boolean、void作为方法的返回值
public Integer updateEmployee(Employee employee);

2.返回值类型
①:返回 List集合对象类型,只需要指定返回值类型为集合中泛型的类型即可

<!-- public List<Employee> selectAll(); -->

<select id="selectAll" resultType="com.nengjie.mybatis.bean.Employee"

      select * from tbl_employee
</select>

②:查询单条记录封装为Map,此时,返回值类型只需要使用 Map类型即可;

<!-- public Map<String, Employee> selectEmployeeMapById(Integer id); -->

<select id="selectEmployeeMapById" resultType="map"

      select * from tbl_employee where id = #{id}
</select>
③:查询多条记录封装为Map,如我们返回Map<String,Employee>类型的Map,使用 resultType指定value的类型;
          使用@MapKey注解来指定POJO的哪个属性作为key

@MapKey("id")

public Map<String, Employee> selectEmployeeMapById(Integer id);

<select id="selectEmployeeMapById" resultType="map">

     
  select * from tbl_employee where id > #{id}

</select>

3.获取自增主键的值:

        mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();

        (JDBC中使用 Statement的getGeneratedKeys()方法来获取自增主键)

        useGeneratedKeys="true";使用自增主键获取主键值策略

        keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性

   <!-- public void addEmployee(Employee employee); -->

        <insert id="addEmployee" useGeneratedKeys="true" keyProperty="id">

            insert
into tbl_employee(last_name,gender,email) values(#{lastName},#{gender},#{email})
        </insert>

4.获取非自增主键的值:

        Oracle不支持自增;Oracle使用序列来模拟自增;

        每次插入的数据的主键是从序列中拿到的值;

5.参数处理:

单个参数:当传入单个参数时,mybatis不会做特殊的处理因为只有一个参数,此时对参数名不会进行严格的检查:
    #{参数名/任意名}:取出参数值。

return args[names.firstKey()];

多个参数:mybatis会做特殊处理。多个参数会被封装成
一个map
        key:param1...paramN,或者参数的索引0,1......也可以

        value:传入的参数值

     
  #{}就是从map中获取指定的key的值;

<select id="selectEmployeeByNameAndId" resultType="com.nengjie.mybatis.bean.Employee">

select * from tbl_employee where last_name = #{param1} and id = #{param2}
</select>
    异常:

    org.apache.ibatis.binding.BindingException: 

    Parameter 'id' not found. 

    Available parameters are [1, 0, param1, param2]

    解决方法:使用#{index}或者#{paramN}

    缺点:当有多个参数时,可读性差

为了解决上述问题,使用【命名参数】:明确指定封装参数时map的key;@Param("id")

    多个参数会被封装成 一个map,

        key:使用@Param注解指定的值

        value:参数值

    #{指定的key}取出对应的参数值
public Employee selectEmployeeByNameAndId(@Param("lastName")String name, @Param("id")Integer id);


<select id="selectEmployeeByNameAndId" resultType="com.nengjie.mybatis.bean.Employee">

        select * from tbl_employee
where last_name = #{last_name} and id = #{id}
</select>
mybatis的对参数的处理的源码分析:

public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    
       //1、参数为null直接返回
    if (args == null || paramCount == 0) {
      return null;

     //2、如果只有一个元素,并且没有Param注解;args[0]:单个参数直接返回
    } else if (!hasParamAnnotation && paramCount == 1) {
      return args[names.firstKey()];

    //3、多个元素或者有Param标注
    } else {
      final Map<String, Object> param = new ParamMap<Object>();
      int i = 0;
10cd3

       //4、遍历names集合;{0=id, 1=lastName,2=2}
      for (Map.Entry<Integer, String> entry : names.entrySet()) {

        
             //names集合的value作为key; names集合的key又作为取值的参考args[0]:args【1,"Tom"】:
             //eg:{id=args[0]:1,lastName=args[1]:Tom,2=args[2]}
        param.put(entry.getValue(), args[entry.getKey()]);

             //额外的将每一个参数也保存到map中,使用新的key:param1...paramN
             //效果:有Param注解可以#{指定的key},或者#{param1}
        // add generic param names (param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  }
}

POJO:

如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;

#{属性名}:取出传入的pojo的属性值 

public Employee selectEmployeeByNameAndId(Employee employee);


    <select id="selectEmployeeByNameAndId" resultType="com.nengjie.mybatis.bean.Employee">

    select * from tbl_employee where last_name = #{lastName} and id = #{id}
    </select>

测试方法:

    Employee employee = new Employee(2, "Jack1", nullnull);

    employee = mapper.selectEmployeeByNameAndId(employee);

Map:

如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map

#{key}:取出map中对应的值

public Employee
getEmployeeByMap(Map<String, Object> map); 



    <select id="getEmployeeByMap" resultType="com.nengjie.mybatis.bean.Employee">

        select * from tbl_employee where last_name
= #{lastName} and id = #{id}
    </select>

Map<String, Object> map = new HashMap<String,
Object>();

    map.put("lastName", "Jack1");

    map.put("id", 2);

    Employee employee = mapper.getEmployeeByMap(map);

TO:

如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象

Page{

    int index;

    int size;

}

Collection:

当需要从 Collection 中获取参数时,可以使用 #{collection[index]}来获取指定 index位置的参数值
注意:
如果是 List 集合,还可以使用 #{list[index]}来获取指定 index位置的参数值

如果是数组类型,可以使用 #{array[index]} 来获取指定 index位置的参数值

public Employee getEmployeeByList(Collection<String> name);



    <select id="getEmployeeByList" resultType="com.nengjie.mybatis.bean.Employee">

        select * from tbl_employee
where last_name = #{collection[0]}
    </select>

    List<String> name = new ArrayList<String>();
    name.add("jack1");
    Employee employee = mapper.getEmployeeByList(name);

#{}与${}

相同点:都可以获取map中的值或者pojo对象属性的值;
区别:

        #{}:是以预编译的形式,使用PreparedStatement将参数设置到sql语句中,可以防止sql注入

        ${}:取出的值直接拼装在sql语句中,会有sql注入的安全问题;

        大多情况下,我们取参数的值都应该去使用#{};

${}的使用场景:
        原生jdbc不支持占位符的地方我们就可以使用${}进行取值

        比如分表、排序。。。;按照年份分表拆分

#{}对null值的处使用 PageInfo 对结果进行封装理:我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错);使用 PageInfo 对结果进行封装

二、ResultMap
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息