• mybatis输入输出映射——(五)


    0.#{}与${}区别

    #{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?。

    <!-- 根据id查询用户信息 -->
    	<select id="findUserById" parameterType="int" resultType="user">
    		select * from user where id = #{id}
    	</select>
    

      

    使用占位符#{}可以有效防止sql注入,在使用时不需要关心参数值的类型,mybatis会自动进行java类型和jdbc类型的转换。#{}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称

    ${}和#{}不同,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。使用${}不能防止sql注入,但是有时用${}会非常方便,如下的例子:

    <!-- 根据名称模糊查询用户信息 -->
    	<select id="selectUserByName" parameterType="string" resultType="user">
    	   select * from user where username like '%${value}%'
    	</select>
    

      

    如果本例子使用#{}则传入的字符串中必须有%号,而%是人为拼接在参数中,显然有点麻烦,如果采用${}在sql中拼接为%的方式则在调用mapper接口传递参数就方便很多。

    再比如order by排序,如果将列名通过参数传入sql,根据传的列名进行排序,应该写为:

    ORDER BY ${columnName}

    如果使用#{}将无法实现此功能。

    实际可以这么理解,#{}会在里面加上单引号。${}不会加上单引号。比如:

    如果变量的值是:safehatnum

    (1)#{}加引号

    select * from safehat order by #{order};

    相当于

    select * from safehat order by 'safehatnum';

    (2)${}不加引号

    select * from safehat order by ${order};

    相当于

    select * from safehat order by safehatnum;

    --------------------------------parameterType输入类型--------------------

    通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型

    1     传递简单类型

    1.int型

    2.String型

    <select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
            SELECT * FROM USER WHERE username like '%${value}%'
        </select>

    2. 传递POJO对象

    Mybatis使用ognl表达式解析对象字段的值,如下例子:

       <!-- 更新用户,根据Id更新 ,需要传入Id(int型)与更新信息
        parameterType类型为User类型,指定需要修改的用户id和修改后的属性值,#{username}表示从传入的对象中取对应的username属性
        #{id}表示从user对象中获取id
        -->
        <update id="updateUserByTd" parameterType="cn.itcast.mybatis.po.User">
        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
        where id=#{id}
        </update>

    异常测试:

    Sql中字段名输入错误后测试,username输入dusername测试结果报错:

    org.apache.ibatis.exceptions.PersistenceException: 
    ### Error querying database.  Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'dusername' in 'class cn.itcast.mybatis.po.User'
    ### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'dusername' in 'class cn.itcast.mybatis.po.User'
    

      

     

    3. 传递pojo包装对象(传递QueryVo,取值的时候取其属性User对象的属性,相当于取传的对象的属性的属性,只不过对象的属性是对象)

       开发中通过pojo传 递查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。

    3.1  定义包装对象

    定义包装对象将查询条件(pojo)以类组合的方式包装起来。

    3.2   mapper.xml映射文件

    说明:mybatis底层通过ognl从pojo中获取属性值:#{user.username},user即是传入的包装对象的属性。queryVo是别名,即上边定义的包装对象类型。

    4.  传递hashmap

    Sql映射文件定义如下:

    <!-- 传递hashmap综合查询用户信息 -->
        <select id="findUserByHashmap" parameterType="hashmap" resultType="user">
           select * from user where id=#{id} and username like '%${username}%'
        </select>

    上边红色标注的是hashmap的key。

    测试:

    Public void testFindUserByHashmap()throws Exception{
            //获取session
            SqlSession session = sqlSessionFactory.openSession();
            //获限mapper接口实例
            UserMapper userMapper = session.getMapper(UserMapper.class);
            //构造查询条件Hashmap对象
            HashMap<String, Object> map = new HashMap<String, Object>();
            map.put("id", 1);
            map.put("username", "管理员");
            
            //传递Hashmap对象查询用户列表
            List<User>list = userMapper.findUserByHashmap(map);
            //关闭session
            session.close();
        }

    异常测试:

    传递的map中的key和sql中解析的key不一致。

    测试结果没有报错,只是通过key获取值为空。

    5.传递List

    sql定义:(输入类型为List,collection定义为list)

        <select id="getQuestionsForExamPaper" parameterType="java.util.List"
            resultMap="questionAndOptionForPaper">
            SELECT * FROM questions q,options o WHERE
            q.questionId=o.questionId and
            q.questionId in
            <foreach collection="list" item="id" separator="," open="("
                close=")">
                #{id}
            </foreach>
        </select>

    Java 测试:

        // 测试根据ID集合查询试题
        @Test
        public void test2() throws SQLException {
            Map<String, Object> condition = new HashMap<String, Object>();
            condition.put("type", "单选题");
            condition.put("level", 1);
            condition.put("num", 3);
            List<String> IDs = questionsCustomMapper.getQuestionsIdsForExamPaper(condition);
            List<Questions> questions = questionsCustomMapper.getQuestionsForExamPaper(IDs);
            System.out.println(questions.size());
        }

     foreach 的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有 item,index,collection,open,separator,close。item表示集合中每一个元素进行迭代时的别名,index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔 符,close表示以什么结束,在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况: 

      1. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .
      2. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .
      3. 如 果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也 是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map 里面的key.

    ------------------------------------resultType输出类型----------------------------------------

    1. 输出简单类型

    Mapper.xml文件

    <!-- 获取用户列表总数 -->
    
        <select id="findUserCount" parameterType="user" resultType="int">
    
           select count(1) from user
    
        </select>

    Mapper接口

    public int findUserCount(User user) throws Exception;

    测试:

    Public void testFindUserCount() throws Exception{
    
           //获取session
    
           SqlSession session = sqlSessionFactory.openSession();
    
           //获取mapper接口实例
    
           UserMapper userMapper = session.getMapper(UserMapper.class);
    
       
    
           User user = new User();
    
           user.setUsername("管理员");
    
    
           int count = userMapper.findUserCount(user);
    
          
    
           //关闭session
    
           session.close();
    
        }

    总结:

    输出简单类型必须查询出来的结果集有一条记录,最终将第一个字段的值转换为输出类型。

    使用session的selectOne可查询单条记录。

     2.   输出pojo对象

    Mapper.xml

       <!-- 根据id查询用户信息 -->
    
        <select id="findUserById" parameterType="int" resultType="user">
    
           select * from user where id = #{id}
    
        </select>

    Mapper接口:

    public User findUserById(int id) throws Exception;

    测试:

    Public void testFindUserById() throws Exception {
    
           //获取session
    
           SqlSession session = sqlSessionFactory.openSession();
    
           //获限mapper接口实例
    
           UserMapper userMapper = session.getMapper(UserMapper.class);
    
           //通过mapper接口调用statement
    
           User user = userMapper.findUserById(1);
    
           System.out.println(user);
    
           //关闭session
    
           session.close();
    
        }

    使用session调用selectOne查询单条记录。

    3.    输出pojo列表(list集合)

    Mapper.xml

    <!-- 根据名称模糊查询用户信息 -->
    
        <select id="findUserByUsername" parameterType="string" resultType="user">
    
           select * from user where username like '%${value}%'
    
        </select>

    Mapper接口:

    public List<User> findUserByUsername(String username) throws Exception;

    测试:

    Public void testFindUserByUsername()throws Exception{
    
           //获取session
    
           SqlSession session = sqlSessionFactory.openSession();
    
           //获限mapper接口实例
    
           UserMapper userMapper = session.getMapper(UserMapper.class);
    
           //如果使用占位符号则必须人为在传参数中加%
    
           //List<User> list = userMapper.selectUserByName("%管理员%");
    
           //如果使用${}原始符号则不用人为在参数中加%
    
           List<User> list = userMapper.findUserByUsername("管理员");
    
           //关闭session
    
           session.close();
    
        }

    使用session的selectList方法获取pojo列表。

    4.   输出hashmap(一般不用,在需要查询指定列并转为接送的时候可以使用)

      输出pojo对象可以改用hashmap输出类型,将输出的字段名称作为map的key,value为字段值。

      这样一个语句简单作用于所有列被自动映射到 HashMap 的键上,这由 resultType 属性指定。这在很多情况下是有用的,但是 HashMap 不能很好描述一个领域模型。那样你的应用程序将会使用 JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 对象)来作为领域模型。

        <!-- S 查询部门树 -->
        <select id="getDepartmentTreeForExam" resultType="map">
            SELECT
            departmentId,upDepartmentId,departmentName FROM department
        </select>
        <!-- E 查询部门树 -->

    mapper接口:

        /**
         * 查询部门id,上级id,部门名称生成内部部门树
         * 
         * @return 一个map包含部门的部门id,上级id,部门名称
         * @throws SQLException
         */
        public List<Map<String,Object>> getDepartmentTreeForExam() throws SQLException;

    测试:

    package cn.xm.exam.test.daoTest;
    
    import java.sql.SQLException;
    import java.util.List;
    import java.util.Map;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import cn.xm.exam.mapper.employee.in.custom.DepartmentCustomMapper;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:spring/applicationContext-*.xml")
    public class DepartmentCustomMapperTest {
        @Autowired
        private DepartmentCustomMapper departmentCustomMapper;
    
        @Test
        public void testGeneDepartmentTree() throws SQLException {
            List<Map<String, Object>> departmentTree = departmentCustomMapper.getDepartmentTreeForExam();
            System.out.println(departmentTree);
        }
    
    }

    结果:

    [{departmentId=10, departmentName=厂级-1}, {departmentId=10001, departmentName=部门1_10, upDepartmentId=10}, {departmentId=10001001, departmentName=班组1_10001, upDepartmentId=10001}, {departmentId=10002, departmentName=部门2_10, upDepartmentId=10}, {departmentId=10002001, departmentName=班组2_10002, upDepartmentId=10002}, {departmentId=10003, departmentName=部门3_10, upDepartmentId=10}, {departmentId=11, departmentName=厂级-2}, {departmentId=11001, departmentName=部门1_11, upDepartmentId=11}, {departmentId=12, departmentName=厂级-3}]

     5.输出Set集合(去掉重复元素)

    接口:

        /**
         * 根据用户ID查询用户所有的角色名称
         * @param userId    用户ID
         * @return
         * @throws SQLException
         */
        public Set<String> getUserRoleNameByUserId(@Param("userId") String userId)throws SQLException;

    XML实现:

        <!--4.根据userid查询所有的用户角色名称-->
        <select id="getUserRoleNameByUserId" resultType="string" parameterType="string">
            SELECT DISTINCT
              roleName
            FROM role
            WHERE roleid IN(SELECT
                              roleid
                            FROM user_role
                            WHERE userid = #{userId})
        </select>

    resultType总结:

      输出pojo对象和输出pojo列表在sql中定义的resultType是一样的。

      返回单个pojo对象要保证sql查询出来的结果集为单条,内部使用session.selectOne方法调用,mapper接口使用pojo对象作为方法返回值。

      返回pojo列表表示查询出来的结果集可能为多条,内部使用session.selectList方法,mapper接口使用List<pojo>对象作为方法返回值。

    ---------------------- ----------- resultMap输出结果---------------------------------------------

      resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。

             如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。

             resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。

    1  Mapper.xml定义

    2.  定义resultMap

    <!-- 定义resultMap
        将SELECT id id_,username username_ FROM USER 和User类中的属性作一个映射关系
        
        type:resultMap最终映射的java对象类型,可以使用别名
        id:对resultMap的唯一标识
         -->
         <resultMap type="user" id="userResultMap">
             <!-- id表示查询结果集中唯一标识 
             column:查询出来的列名
             property:type指定的pojo类型中的属性名
             最终resultMap对column和property作一个映射关系 (对应关系)
             -->
             <id column="id_" property="id"/>
             <!-- 
             result:对普通名映射定义
             column:查询出来的列名
             property:type指定的pojo类型中的属性名
             最终resultMap对column和property作一个映射关系 (对应关系)
              -->
             <result column="username_" property="username"/>
         
         </resultMap>

    <id />:此属性表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个<id />。

    Property:表示person类的属性。

    Column:表示sql查询出来的字段名。

    Column和property放在一块儿表示将sql查询出来的字段映射到指定的pojo类属性上。

    <result />:普通结果,即pojo的属性。

    3.  Mapper接口定义

    public List<User> findUserListResultMap() throws Exception;

     参考:http://www.cnblogs.com/qlqwjy/p/7295426.html

  • 相关阅读:
    应用实例:用户登录(2009.10.23)
    ASP.NET学习笔记:服务器控件 (2009.11.9)
    小实例:模拟电话簿
    用Iframe实现左边TreeView导航,右边显示相应内容的布局
    HTML&CSS&JaveScript学习笔记(2009.11.19)
    C#中问号(?)的用法
    GridView的简单分页等
    GridView正反双向排序
    代码理解(2009.11.20)
    ASP.NET学习笔记:数据库操作 (2009.11.10)
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/7295268.html
Copyright © 2020-2023  润新知