zoukankan      html  css  js  c++  java
  • mybatis-sql映射文件

    一、增删改查

    • mybatis允许增删改的方法直接定义返回值为Integer、Long、Boolean、void这些类型的,mybatis会自动帮我们封装返回值
    • sqlSessionFactory.openSession(),获取到的SqlSession不会自动提交数据,我们需要手动提交数据;sqlSessionFactory.openSession(true);===》自动提交

    映射插入语句

    • 自增主键添加

    mysql支持自增主键
      useGeneratedKeys="true";使用自增主键获取主键值策略
      keyProperty="id";指定对应的主键属性;

    mybatis利用statement.getGenreatedKeys()获取到自增主键值后,将这个值封装给javaBean的哪个属性;不定义的话对象是获取不到id值的

        <insert id="addEmp" parameterType="com.mybatis.bean.Employee"
            useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
            insert into tbl_employee(last_name,email,gender) 
            values(#{lastName},#{email},#{gender})
        </insert>
    • 非自增主键添加

    Oracle不支持自增,Oracle使用序列来模拟自增,每次插入的数据的主键是从序列中拿到的值;
      keyProperty:查出的主键值封装给javaBean的哪个属性
    order="BEFORE":先运行selectKey查询id的sql;查出id值封装给javaBean的id属性
         resultType:查出的数据的返回值类型
        <insert id="addEmp" databaseId="oracle">
            <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
                select EMPLOYEES_SEQ.nextval from dual 
            </selectKey>
            
            insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
            values(#{id},#{lastName},#{email<!-- ,jdbcType=NULL -->}) 
        </insert>
      
    order="AFTER":先运行插入的sql(从序列中取出新值作为id);再运行selectKey查询id的sql;
    ps:如果同时插入多条数据,这样获取到的序列值不是当前插入的id
     <insert id="addEmp" databaseId="oracle">
            <selectKey keyProperty="id" order="AFTER" resultType="Integer">
             select EMPLOYEES_SEQ.currval from dual
            </selectKey>
           
            insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
            values(employees_seq.nextval,#{lastName},#{email}) 
        </insert>

    映射删除语句

    <delete id="deleteEmpById">
        delete from tbl_employee where id=#{id}
    </delete>

    映射更新语句

    <update id="updateEmp">
            update tbl_employee 
            set last_name=#{lastName},email=#{email},gender=#{gender}
            where id=#{id}
    </update>

    映射查询语句

    <select id="getEmpById" resultType="com.mybatis.bean.Employee">
            select * from tbl_employee where id = #{id}
    </select>

    代码

    @Test
        public void test03() throws IOException{
            
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
            //获取到的SqlSession不会自动提交数据
            SqlSession openSession = sqlSessionFactory.openSession();
            
            try{
                EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
                //测试添加
                Employee employee = new Employee(null, "jerry4",null, "1");
                mapper.addEmp(employee);
                System.out.println(employee.getId());
                
                //测试修改
                //Employee employee = new Employee(1, "Tom", "jerry@com", "0");
                //boolean updateEmp = mapper.updateEmp(employee);
                //System.out.println(updateEmp);
                //测试删除
                //mapper.deleteEmpById(2);
                //手动提交数据
                openSession.commit();
            }finally{
                openSession.close();
            }

    二、参数处理

    • sql映射文件中的参数类型parameterType可以省略,mybatis会根据TypeHandle自动判断;个人认为如果写入的话能让开发者更清楚对应的是哪个JavaBean类或者哪种数据结构。
    • returnType定义别名或全类名

    mybatis传入参数

    1、单个参数:mybatis不会做特殊处理,#{参数名/任意名}:取出参数值。

    2、多个参数:mybatis会做特殊处理。多个参数会被封装成 一个map,mybatis会帮我们把多个参数的key定义成param1...paramN

    key:param1...paramN,或者参数的索引也可以
    value:传入的参数值
    #{}就是从map中获取指定的key的值;

      如果我们按照接口方法传入的参数名称去获取会出现以下异常

    操作:
    方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
    取值:#{id},#{lastName}
    
    
    异常:
    org.apache.ibatis.binding.BindingException: 
    Parameter 'id' not found. 
    Available parameters are [1, 0, param1, param2]
    View Code

    解决方法有2种:

    • #{param1},#{param2}取值即可,但这种方式不能见名知意
    • 命名参数:明确指定封装参数时map的key;在方法参数前加上@Param("参数名"),这样key就会使用@Param注解指定的值
    public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);

     3、POJO:如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;#{属性名}:取出传入的pojo的属性值

    4、Map:如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map;#{key}:取出map中对应的值

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

    6、如果参数类型是Collection(List、Set)或者数组也会特殊处理。把传入的list或者数组封装在map中,

    key命名:
    Collection——(collection)
    List——(list)
    数组——(array)

    取值方式
    #{list[0]}

    mybatis获取参数值

    #{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
    ${}:取出的值直接拼装在sql语句中;会有安全问题;

    • 大多情况下,我们取参数的值都应该去使用#{};
    • 原生jdbc不支持占位符的地方我们就可以使用${}进行取值

    #{}更多用法

    参数的一些规则:javaType、 jdbcType、 mode(存储过程)、 numericScale、resultMap、 typeHandler、 jdbcTypeName、 expression(未来准备支持的功能)

    ps:在我们传入数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错);这是因为mybatis在全局配置中对所有的null映射的是原生Jdbc的OTHER类型,而oracle不能识别JdbcType OTHER(无效的类型):

    两种解决方案

    1、#{email,jdbcType=OTHER};
    2、修改全局配置jdbcTypeForNull属性的值<setting name="jdbcTypeForNull" value="NULL"/>

    ${}使用场景

    比如分表、排序。。。;按照年份分表拆分
                select * from ${year}_salary where xxx;
                select * from tbl_employee order by ${f_name} ${order}

    mybatis返回结果集

    • resultType指定期望结果集的全类名或别名,如果数据模型与数据库字段名称不匹配,可以开启驼峰命名或者在sql写别名的方式对应起来

    以简单数据结构返回的这里就省略了;这里主要说下list、map以及指定相应泛型的方法。

    如果返回的是一个list,要写集合中元素的类型,而不是list(resultType="javaBean的全类名/别名");我们想要的就是javaBean,只是结果有多条,mybatis会帮我们自动写入到一个list返回给我们

    如果返回的是一条记录的map;key就是列名,值就是对应的值(resultType="map")

    如果是多条记录封装一个map,比如Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javaBean,我们可以通过@MapKey告诉mybatis封装这个map的时候使用哪个属性作为map的key;而它的resultType="javaBean的全类名/别名"

    @MapKey("id")
    public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);

    总结:returnType始终写的是我们想要mybatis把每一条记录封装成什么类型,无论是list还是多条记录的map,我们真正想要的是JavaBean的数据模型,mybatis会帮我们把这些数据封装成我们定义的方法返回类型

    • resultMap:自定义某个javaBean的封装规则

        type:自定义规则的java类型
        id:唯一id方便引用

    1、简单查询

    <resultMap type="com.mybatis.bean.Employee" id="MySimpleEmp">
            <!--指定主键列的封装规则
            id定义主键会底层有优化;
            column:指定哪一列
            property:指定对应的javaBean属性
              -->
            <id column="id" property="id"/>
            <!-- 定义普通列封装规则 -->
            <result column="last_name" property="lastName"/>
            <!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 -->
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
    </resultMap>
        <select id="getEmpById"  resultMap="MySimpleEmp">
            select * from tbl_employee where id=#{id}
        </select>

    2、联合查询(封装单对象)

    • 嵌套结果集的方式,级联属性封装结果集


    <resultMap type="com.mybatis.bean.Employee" id="MyDifEmp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap>
    • 嵌套结果集的方式,使用association定义关联的单个对象的封装规则

    <resultMap type="com.mybatis.bean.Employee" id="MyDifEmp2">
            <id column="id" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="gender" property="gender"/>
            
            <!--  association可以指定联合的javaBean对象
            property="dept":指定哪个属性是联合的对象
            javaType:指定这个属性对象的类型[不能省略]
            -->
            <association property="dept" javaType="com.mybatis.bean.Department">
                <id column="did" property="id"/>
                <result column="dept_name" property="departmentName"/>
            </association>
        </resultMap>
    <select id="getEmpAndDept" resultMap="MyDifEmp">
      SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
      d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
      WHERE e.d_id=d.id AND e.id=#{id}
    </select>
    <select id="getEmpAndDept" resultMap="MyDifEmp">
      SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
      d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
      WHERE e.d_id=d.id AND e.id=#{id}
    </select>
    • 使用association进行分步查询

    <resultMap type="com.mybatis.bean.Employee" id="MyEmpByStep">
             <id column="id" property="id"/>
             <result column="last_name" property="lastName"/>
             <result column="email" property="email"/>
             <result column="gender" property="gender"/>
             <!-- association定义关联对象的封装规则
                 select:表明当前属性是调用select指定的方法查出的结果(namespace+标识id)
                 column:指定将哪一列的值传给这个方法作为传参的参数
              -->
             <association property="dept" 
                 select="com.mybatis.dao.DepartmentMapper.getDeptById"
                 column="d_id">
             </association>
    </resultMap>
    //引用MyEmpByStep,它会根据加载策略进行二次查询
    <select id="getEmpByIdStep" resultMap="MyEmpByStep">
             select * from tbl_employee where id=#{id}
    </select>
    
    //dept部分 <select id="getDeptById" resultType="com.mybatis.bean.Department">   select id,dept_name departmentName from tbl_dept where id=#{id} </select>

    3、联合查询(封装Collection)

    • 嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则
    <resultMap type="com.mybatis.bean.Department" id="MyDept">
            <id column="did" property="id"/>
            <result column="dept_name" property="departmentName"/>
            <!-- 
                collection定义关联集合类型的属性的封装规则 
                ofType:指定集合里面元素的类型
            -->
            <collection property="emps" ofType="com.mybatis.bean.Employee">
                <!-- 定义这个集合中元素的封装规则 -->
                <id column="eid" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="email" property="email"/>
                <result column="gender" property="gender"/>
            </collection>
        </resultMap>
    <select id="getDeptByIdPlus" resultMap="MyDept">
            SELECT d.id did,d.dept_name dept_name,
                    e.id eid,e.last_name last_name,e.email email,e.gender gender
            FROM tbl_dept d
            LEFT JOIN tbl_employee e
            ON d.id=e.d_id
            WHERE d.id=#{id}
    </select>
    • 使用collection进行分段查询 

    <resultMap type="com.mybatis.bean.Department" id="MyDeptStep">
            <id column="id" property="id"/>
            <id column="dept_name" property="departmentName"/>
            <collection property="emps" 
                select="com.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
                column="id"></collection>   
    //如果需要多个查询条件的话,使用map进行传递column="{key1=column1,key2=column2}",其中key1是getEmpsByDeptId获取的参数名,column1是我们传递过去的属性值{deptId=id}
    </resultMap>

    <select id="getDeptByIdStep" resultMap="MyDeptStep">
      select id,dept_name from tbl_dept where id=#{id}
    </select>

    鉴别器

      可以使用discriminator判断某列的值,然后根据某列的值改变封装行为

         <resultMap type="com.mybatis.bean.Employee" id="MyEmpDis">
             <id column="id" property="id"/>
             <result column="last_name" property="lastName"/>
             <result column="email" property="email"/>
             <result column="gender" property="gender"/>
             <!-- column:指定判定的列名;javaType:列值对应的java类型  -->
             <discriminator javaType="string" column="gender">
                 <!--  如果=0,查询出dept的信息  -->
                 <case value="0" resultType="com.mybatis.bean.Employee">
                     <association property="dept" 
                         select="com.mybatis.dao.DepartmentMapper.getDeptById"
                         column="d_id">
                     </association>
                 </case>
                 <!--  如果=1,把last_name这一列的值赋值给email  -->
                 <case value="1" resultType="com.mybatis.bean.Employee">
                     <id column="id" property="id"/>
                     <result column="last_name" property="lastName"/>
                     <result column="last_name" property="email"/>
                     <result column="gender" property="gender"/>
                 </case>
             </discriminator>
         </resultMap>

    延迟加载(按需加载)

    • 使用分步查询可以使用全局配置文件制定延迟加载策略
    <!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="aggressiveLazyLoading" value="false"/> 
    • 也可在collection或association里加入fetchType

    fetchType="lazy"  - lazy:延迟  - eager:立即
  • 相关阅读:
    mac-chrome下手动安装vue-devtools
    python生成随机数、随机字符串
    windows下基于sublime text3的nodejs环境搭建
    解决webstorm卡顿问题
    【更改表单元素默认样式】更改文件上传按钮样式
    JavaScript判断用户是通过电脑端还是移动端访问
    【转载自W3CPLUS】如何将页脚固定在页面底部
    【前端插件】图片上传插件收集
    AngularJS 表单提交后显示验证信息与失焦后显示验证信息
    【转】包管理器Bower详细讲解
  • 原文地址:https://www.cnblogs.com/edda/p/13416162.html
Copyright © 2011-2022 走看看