MyBatis映射文件(编写SQL语句;可有可无(无的时候,使用注解编程))

摘要:
--Oracle不支持自动增量;Oracle使用序列模拟自动增量;每个插入数据的主键是从序列中获得的值;如何获取此值--˃/*keyProperty:Java bean的哪个属性由找到的主键值order=“AFTER”封装:当前SQL在插入SQL后执行resultType:找到数据的返回值类型*//*编写SQL语句以查询主键以获取当前序列值*/选择序列名称。currvalfromdual插入tbl_Employeevalues3.映射文件-参数处理单个参数:MyBatis不进行特殊处理。
 一、映射文件

MyBatis映射文件(编写SQL语句;可有可无(无的时候,使用注解编程))第1张

 1.简单的增删改(需要commit)---查

MyBatis允许增删改直接定义以下类型返回值

  Integer、Long、Boolean、void

我们需要手动提交数据。

  sqlSessionFactory.openSession();===>需要手动提交

  sqlSessionFactory.openSession(true);===>自动提交

2.获取insert-自增的主键

JDBC中Statement的方法:getGeneratedKeys();--->获取由于执行此Statement对象而创建的所有自动生成的键。

    <!--自增主键的值
    获取
        mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGeneratedKeys();
        useGeneratedKeys="true":使用自增主键获取主键值策略
        keyProperty:指定对应的主键属性,也就是mybatis获取到主键值之后,将这个值封装给JavaBean的哪个属性
    -->
    <insert id="addEmp" parameterType="emp" useGeneratedKeys="true" keyProperty="id">
        insert into tbl_employee(last_name,email,gender)
      values(#{lastName},#{email},#{gender})
    </insert>

Oracle:自增的序列

MyBatis映射文件(编写SQL语句;可有可无(无的时候,使用注解编程))第2张

~~ before:从序列中查主键的SQL在插入SQL之前执行

    <!--
        Oracle不支持自增;Oracle使用序列来模拟自增;
        每次插入的数据的主键是从序列中拿到的值;如何获取到这个值
    -->
    <insert id="addEmp" databaseId="oracle" parameterType="emp">

        /*
        keyProperty:查出的主键值封装给Javabean的哪个属性
        order="BEFORE":当前SQL在插入SQL之前执行
        resultType:查出数据的返回值类型
        */
        <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
            /*编写查询主键的SQL语句*/
            select 序列名.nextval from dual
        </selectKey>

       /*插入时的主键是从序列中拿到的*/
       insert into tbl_employee(id,last_name,email,gender)
       values (#{id},#{lastName},#{email},#{gender})
    </insert>

 ~~after:

    <!--
        Oracle不支持自增;Oracle使用序列来模拟自增;
        每次插入的数据的主键是从序列中拿到的值;如何获取到这个值
    -->
    <insert id="addEmp" databaseId="oracle" parameterType="emp">

        /*
        keyProperty:查出的主键值封装给Javabean的哪个属性
        order="AFTER":当前SQL在插入SQL之后执行
        resultType:查出数据的返回值类型
        */
        <selectKey keyProperty="id" order="AFTER" resultType="Integer">
            /*编写查询主键的SQL语句
              获取当前的序列值
            */
            select 序列名.currval from dual
        </selectKey>

       insert into tbl_employee(id,last_name,email,gender)
       values (序列名.nextval,#{lastName},#{email},#{gender})
    </insert>

 3.映射文件---参数处理(单个参数&多个参数)

单个参数:MyBatis不会做特殊处理。

  #{参数名}:取出参数值,参数名可以任意写。

多个参数:MyBatis会做特殊处理。

  多个参数会被封装成一份Map,

    key:param1...paramN,或者参数的索引也可以

    value:传入的参数值

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

public Employee getEmpByIdAndLastName(Integer id,String lastName);
    <select id="getEmpByIdAndLastName" resultType="emp">
        select * from tbl_employee where id = #{param1} and last_name = #{param2}
    </select>

命名参数:明确指定封装参数值时map的key;@Param("id")

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

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

    value:参数值

  #{指定的key}:取出对应的参数值

    public Employee getEmpByIdAndLastName(@Param("id") Integer id,@Param("lastName") String lastName);
    <select id="getEmpByIdAndLastName" resultType="emp">
        select * from tbl_employee where id = #{id} and last_name = #{lastName}
    </select>

 4.映射文件---参数处理---POJO&TO

POJO:

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

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

Map:

  如果多个参数不是业务模型中的数据,没有对应的POJO,为了方便,我们也可以传入Map;

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

    public Employee getEmpByMap(Map<String,Object> map);
    <select id="getEmpByMap" resultType="emp">
        select * from tbl_employee where id=#{id} and last_name=#{lastName}
    </select>
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

        Map<String,Object> map = new HashMap<String, Object>();
        map.put("id",2);
        map.put("lastName","jesscia");
        Employee jesscia = mapper.getEmpByMap(map);

        System.out.println(jesscia);

TO: 

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

   例如:分页时的Page类。

 5.映射文件---参数处理---参数封装扩展思考

    public Employee getEmp(@param("id")Integer id,String lastName);

  取值:id===>#{id/param1}  last_name===>#{param2}

public Employee getEmp((Integer id,@param("e")Employee emp);

  取值:id===>#{param1}  last_name===>#{param2.lastName/e,lastName}

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

  key:Collection(collection),如果是List还可以使用这个key(list)

    public Employee getEmpById(List<Integer> ids);

  取值:取出第一个id值: #{list[0]}

===============可以结合MyBatis源码,看怎样处理参数。=============

6.映射文件===参数处理===#与$取值区别

#{ }:可以获取map中的值或者POJO对象属性的值;

${ }:可以获取map中的值或者POJO对象属性的值;

select * from tbl_employee where id=${id} and last_name=#{lastName}

Preparing: select * from tbl_employee where id=2 and last_name=?

  区别:

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

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

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

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

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

        select * from ${year}_salary where xxx;

        select * from tbl_employee order by ${f_name};按照什么排序

7.映射文件===参数处理===#取值时指定参数相关规则

 #{ }:更丰富的用法;

  规定参数的一些规则:

  javaType、jdbcType、mode(存储过程)、numericScale、

  resultMap、typeHandler、jdbcTypeName、expression(未来准备支持的功能)

  jdbcType通常需要在某种特定的条件下被设置:

    在我们数据为null的时候,有些数据库可能不能识别mybatis对null的处理。比如Oracle(报错);

     JdbcType OTHER:无效的类型;因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,Oracle不能正确处理

    MyBatis里有JdbcType枚举类,与数据库中的各种类型进行映射。

     例如:#{email, JdbcType=NULL},在Oracle环境下,如果email为NUll,怎会出现JdbcType OTHER错误,把JdbcType改为NULL就行。即#{email,JdbcType=NULL}。

     

  由于全局配置中:jdbcTypeForNull=OTHER;Oracle不支持;两种解决方法:

  1、#{email,  jdbcType=NULL};

  2、jdbcTypeForFull=NULL

    <setting  name="jdbcTypeForNull"  value="NULL"/> 在全局配置文件中设置

7.映射文件===select返回List

 MyBatis映射文件(编写SQL语句;可有可无(无的时候,使用注解编程))第3张

resultType: 如果返回是一个集合,要写集合中元素的类型。

    public List<Employee> getEmpsByLastNameLike(String lastName);
    <select id="getEmpsByLastNameLike" resultType="emp">
        select * from tbl_employee where last_name like #{lastName}
    </select>
        List<Employee> list = mapper.getEmpsByLastNameLike("%s%");
        System.out.println("list:"+list);

8.映射文件===select记录封装Map

 返回一条记录的map;key就是列名,值就是对应的值

    //返回一条记录的map;key就是列名,值就是对应的值
    public Map<String,Object> getEmpByIdReturnMap(Integer id);
    <select id="getEmpByIdReturnMap" resultType="map">
      select * from tbl_employee where id=#{id}
    </select>
        //单条记录的key值是列名
        Map<String, Object> map = mapper.getEmpByIdReturnMap(2);
        String lastName = (String) map.get("last_name");

 返回多条记录封装到map中:===注解@MapKey的使用:告诉MyBatis封装的时候使用哪个属性作为map的key

    //多条记录封装一个Map:Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的Javabean
    //告诉Mybatis封装这个Map的时候使用哪个属性作为map的key。
    @MapKey("id")
    public Map<Integer,Employee> getEmpByLastNameLikeReturnMap(String lastName);
    <select id="getEmpByLastNameLikeReturnMap" resultType="emp">
      select * from tbl_employee where last_name like #{lastName}
    </select>
        Map<Integer, Employee> map = mapper.getEmpByLastNameLikeReturnMap("%s%");

 9.映射文件===select_resultMap===自定义结果映射规则

MyBatis映射文件(编写SQL语句;可有可无(无的时候,使用注解编程))第4张

 自动映射:

MyBatis映射文件(编写SQL语句;可有可无(无的时候,使用注解编程))第5张

 自定义resultMap,高级映射:

    <!--自定义某个Javabean的封装规则
        type:自定义规则的java类型
        id:唯一id,方便引用
    -->
    <resultMap id="MyEmp" type="com.atguigu.mybatis.bean.Employee">
        <!--指定主键列的封装规则
            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>

    <!--resultMap:自定义结果集映射规则;-->
    <select id="getEmpById" resultMap="MyEmp">
        select * from tbl_employee where id=#{id}
    </select>

 10.映射文件===select_resultMap===关联查询_环境搭建

数据库准备:

/*创建部门表*/
CREATE TABLE tbl_dept(
    id int(11) PRIMARY KEY auto_increment,
    dept_name VARCHAR(255)
)

/*向表Employee中插入一列*/
ALTER TABLE tbl_employee ADD COLUMN d_id INT(11);

/*添加约束,外键关联*/
ALTER TABLE tbl_employee ADD CONSTRAINT fk_emp_dept
FOREIGN KEY(d_id) REFERENCES tbl_dept(id)

/*查*/
SELECT e.id id,e.last_name last_name,e.gender gender,e.email email,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=2

在Employee类中增加所属部门(另一个类)信息。

    public Employee getEmpAndDept(Integer id);
    <!--
        场景一:
            查询Employee的同时查询员工对应的部门
            Employee====Department
            一个员工有与之对应的部门信息;
    -->
    <!-- 联合查询:级联属性封装结果集 -->
    <resultMap id="MyDifEmp" type="emp">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>
        <result column="did" property="dept.id"/>
        <result column="dept_name" property="dept.departmentName"/>
    </resultMap>
    <select id="getEmpAndDept" resultMap="MyDifEmp">
        SELECT e.id id,e.last_name last_name,e.gender gender,e.email email,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>
        Employee empAndDept = mapper.getEmpAndDept(2);

        System.out.println(empAndDept);
        System.out.println(empAndDept.getDept());

11.映射文件===select_resultMap关联查询association定义关联对象封装规则

    <!--使用association定义关联的单个对象的封装规则-->
    <resultMap id="MyDifEmp2" type="emp">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>

        <!--association:可以指定联合的Javabean对象
            property:指定哪个属性是联合的对象
            javaType:指定属性的java类型[不能省略]
        -->
        <association property="dept" javaType="department">
            <id column="did" property="id"/>
            <result column="dept_name" property="departmentName"/>
        </association>
    </resultMap>

    <select id="getEmpAndDept" resultMap="MyDifEmp2">
        SELECT e.id id,e.last_name last_name,e.gender gender,e.email email,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>

12.映射文件===select_resultMap关联查询association分步查询

    public Employee getEmpByIdStep(Integer id);
    <resultMap id="MyEmpByStep" type="emp">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>

        <!--association:定义关联对象的封装规则
            select:表明当前属性是调用select指定的方法查出的结果
            column:指定将哪一列的值传给这个方法

            流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
            -->
        <association property="dept"
                     select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
                     column="d_id">

        </association>
    </resultMap>
    <!--使用association进行分步查询
        1、先按照员工id查询员工信息
        2、根据查询员工信息中的d_id值去部门表查询部门信息
    -->
    <select id="getEmpByIdStep" resultMap="MyEmpByStep">
      select * from  tbl_employee where id=#{id}
    </select>
<mapper namespace="com.atguigu.mybatis.dao.DepartmentMapper">
    <select id="getDeptById" resultType="department">
        select id,dept_name departmentName from tbl_dept where id=#{id}
    </select>
</mapper>
        Employee empByIdStep = mapper.getEmpByIdStep(2);
        System.out.println(empByIdStep);
        System.out.println(empByIdStep.getDept());

结果:控制台上会出现两次数据库查询

DEBUG 11-16 21:04:50,898 ==>  Preparing: select * from tbl_employee where id=?   (BaseJdbcLogger.java:145) 
DEBUG 11-16 21:04:50,923 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 11-16 21:04:50,949 ====>  Preparing: select id,dept_name departmentName from tbl_dept where id=?   (BaseJdbcLogger.java:145) 
DEBUG 11-16 21:04:50,953 ====> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 11-16 21:04:50,957 <====      Total: 1  (BaseJdbcLogger.java:145) 
DEBUG 11-16 21:04:50,958 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=2, lastName='jesscia', email='jesscia@qq.com', gender='0', dept=Department{id=1, departmentName='开发部'}}
Department{id=1, departmentName='开发部'}

13.映射文件===select_resultMap关联查询association分步查询&延时加载

分步查询:1.可以组合已有的方法来完成复杂功能,2.可以使用延迟加载

 在分步查询的基础之上:延时加载

    <!--可以使用延迟加载
        Employee==>Dept;
            我们每次查询Employee对象时,都将一起查询出来。
            部门信息在我们使用的时候再去查询。
            分步查询的基础之上加上两个配置,
    -->

 在全局配置文件中设置:

    <settings>
        <!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题-->
        <!--打开延时加载的开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--将积极加载改为消极加载及按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/> 
    </settings>

 然后就可以按需加载了。

 14.映射文件===select_resultMap关联查询collection定义关联集合封装规则

场景二:查询部门的时候将部门对应的所有员工信息也查询出来
    public Department getDeptByIdPlus(Integer id)throws Exception;

 嵌套结果集的方式:

    <!--collection:嵌套结果集的方式-->
    <resultMap id="MyDept" type="department">
        <id column="did" property="id"/>
        <result column="dept_name" property="departmentName"/>

            <!--collection:定义关联集合类型的属性的封装规则
                ofType:指定集合里面元素的类型
        -->
        <collection property="emps" ofType="emp">
            <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>

15.映射文件===select_resultMap关联查询collection分步查询&延时加载

    public Department getDeptByIdStep(Integer id);
    <!--==========分步查询===========-->
    <resultMap id="MyDept2" type="department">
        <id column="id" property="id"/>
        <result column="dept_name" property="departmentName"/>

        <collection property="emps"
                    select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDid"
                    column="id">

        </collection>
    </resultMap>
    <select id="getDeptByIdStep" resultMap="MyDept2">
        select id,dept_name departmentName from tbl_dept where id=#{id}
    </select>
    public List<Employee> getEmpsByDid(Integer did);
    <select id="getEmpsByDid" resultType="emp">
      select * from tbl_employee where d_id=#{did}
    </select>

 小扩展:在association和collection中的column属性

 作用:分步查询中的要传递的参数值

当多列的值传递过去:将多列的值封装成map传递;

 column="{key1=column1, key2=column2}"

======================================

fetchType=“lazy”:表示使用延迟加载; 

  -lazy:延迟

  -eager:立即

 16.映射文件===select_resultMap的discriminator鉴别器

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

封装Employee:

  如果查询出的是女生:就把部门信息查询出来,否则不查询;

  如果是男生,把last_name这一列的值赋值给email;

    <resultMap id="MyEmpDis" type="emp">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
        <result column="email" property="email"/>

        <!--column:指定判断的列名
            javaType:列值对应的java类型
        -->
        <discriminator javaType="string" column="gender">
            <!--女生 resultType:指定封装的结果类型-->
            <case value="0" resultType="emp">
                <association property="dept"
                             select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
                             column="d_id">
                </association>
            </case>
            <!--男生-->
            <case value="1" resultType="emp">
                <id column="id" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="gender" property="gender"/>
                <result column="last_name" property="email"/>
            </case>
        </discriminator>
    </resultMap>
    <select id="getEmpByIdStep" resultMap="MyEmpDis">
      select * from  tbl_employee where id=#{id}
    </select>

免责声明:文章转载自《MyBatis映射文件(编写SQL语句;可有可无(无的时候,使用注解编程))》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇一个漂亮的输出MySql数据库表结构的PHP页面vb 实现查找指定的文件,并按照文件名排序下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Jmeter之Bean shell使用(一)

一、什么是Bean Shell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法; BeanShell是一种松散类型的脚本语言(这点和JS类似); BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简的解释器jar文件大小为175k。...

FLINK基础(107): DS算子与窗口(18)窗口 (3) window functions(二)ProcessWindowFunction

ProcessWindowFunction   一些业务场景,我们需要收集窗口内所有的数据进行计算,例如计算窗口数据的中位数,或者计算窗口数据中出现频率最高的值。这样的需求,使用ReduceFunction和AggregateFunction就无法实现了。这个时候就需要ProcessWindowFunction了。 先来看接口定义 public abstr...

Java 性能优化的 50 个细节

在JAVA程序中,性能问题的大部分原因并不在于JAVA语言,而是程序本身。养成良好的编码习惯非常重要,能够显著地提升程序性能。 #尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例 简单来说,单例主要适用于以下三个方面: 控制资源的使用,通过线程同步来控制资源的并发访问; 控制实例的产生,以...

大文件上传 之 改版了的SlickUpload.HttpUploadModule(Krystalware.SlickUpload.dll)

以下代码中所注释的部分是所改版的地方。:)Krystalware.SlickUpload.dll/Files/bigmouthz/SlickUpload.rar------------------------------------------------------using System;using System.Collections;using S...

hadoop26----netty,多个handler

k客户端: package cn.itcast_03_netty.sendorder.client; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; im...

Golang的高级数据类型-切片(slice)实战篇

          Golang的高级数据类型-切片(slice)实战篇                              作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。        切片(slice)是Go中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合,切片是围绕动态数组的概念构建的,可以按需自动增长。   ...