MyBatis-3-MyBatis的sql映射文件

目录

SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):

1:insert, update 和 delete

1.1获取自增主键的值

1.2:获取非自增主键的值

2:参数传递---方法参数向sql映射语句映射

2.1:单个参数

2.2:多个参数

2.3:用@param指定参数(推荐)

2.4:传入pojo(javabean)

2.5:传入map

2.6:传入混合参数

3:参数处理---设定参数的类型和$/#取值

1:参数也可以指定一个特殊的数据类型

2:#{属性名}和${属性名}的区别

4: 查询返回集合list

5: 查询返回map

5.1:查询返回一个map

5.2:查询返回多个map

6:resultMap---自定义封装结果集

6.1:mybait封装结果集时会按照列名和属性名一一对应,如果对应不上就为null;

6.2:自定义resultMap封装结果集

6.3:封装复杂类型的对象(即对象里包含对象);

6.3.1:运用级联属性封装

6.3.2:运用association标签定义对象的封装规则

6.4:查询对象中的封装集合-Collection

7:分步查询和延迟加载(不推荐)

7.1:分部查询

7.1.1:association-分段查询

7.1.2:Collection--分段查询 

7.2:延迟加载

8:动态sql

8.1:if

8.2:where

8.3:trim标签

8.4:foreach

8.5:choose分支选择

8.6:set标签动态修改

8.7:mybatis的ognl表达式以及_parameter参数和_databaseId参数

8.8:sql标签,可重用的标签


SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):

  • cache – 给定命名空间的缓存配置。
  • cache-ref – 其他命名空间缓存配置的引用。
  • resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
  • parameterMap – 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除,这里不会记录。
  • sql – 可被其他语句引用的可重用语句块。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

1:insert, update 和 delete

id命名空间中的唯一标识符,可被用来代表这条语句。
parameterType将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。
parameterMap这是引用外部 parameterMap 的已经被废弃的方法。使用内联参数映射和 parameterType 属性。
flushCache将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句)。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。
statementTypeSTATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。对应原生jdbc的statement;callable为调用存储过程的;
useGeneratedKeys(仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty(仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn(仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
databaseId如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。

1.1获取自增主键的值

1:设置映射文件

<!--让mybatis自动的将自增的id赋值给employee的id属性
    useGeneratedKeys="true" 调用的是原生jdbc的获取自增主键的方法
    keyColumn,将自增主键赋值给哪个字段
-->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
    insert into t_employee(name,email) VALUES(#{name},#{email})
</insert>

2:测试

 /**
     * 新增sql;结束后必须提交
     */
    @Test
    public void test02() {
        //获取和数据库的一次会话;相当于getConnection();
        SqlSession session = sqlSessionFactory.openSession();
        try {
            //使用SqlSession操作数据库,获取到dao接口的实现
            EmployeeDao mapper = session.getMapper(EmployeeDao.class);
            //调用方法得出结果
            Employee abc = new Employee("abc", "aa@qq.com");
            Integer i = mapper.insertEmployee(abc);
            System.out.println("--->"+i);
            System.out.println("--->"+abc.getId());

            session.commit();
        } finally {
            //关闭连接
            session.close();
        }
    }

1.2:获取非自增主键的值

而对于不支持自增型主键的数据库(例如 Oracle ),则可以使用 selectKey 子元素: selectKey  元素将会首先运行 id  会被设置 然后插入语句会被调用
<!--非自增主键-->
<insert id="insertEmployee2" useGeneratedKeys="true" keyProperty="id">

    <selectKey order="BEFORE" resultType="int" keyProperty="id">
        select max(id)+1 from t_employee
    </selectKey>
    insert into t_employee(name,email) VALUES(#{name},#{email})
</insert> 

 selectKey标签

keyPropertyselectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
resultType结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。
order这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入语句内部可能有嵌入索引调用。
statementType与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。

2:参数传递---方法参数向sql映射语句映射

2.1:单个参数

可以接受基本类型,对象类型,集合类型的值。这种情况 MyBatis 可直接使用这个参数,不需要经过任何处理
 
方法:
public Employee getEmployee(Integer id);

映射的sql:

<select id="getEmployee" resultType="com.wkl.bean.Employee">
    select * from t_employee where id =#{id}
</select>

甚至#{haha}都能取到

 

2.2:多个参数

任意多个参数,都会被MyBatis重新包装成一个Map 传入 Map key param1 param2 ,值就是参数的值
这时候#{参数名}就无效了;可以用#{param1}来获取参数,但是注意顺序不能乱
 
方法:
public Employee getEmployee2(Integer id,String name);

sql映射:

<select id="getEmployee2" resultType="com.wkl.bean.Employee">
    select * from t_employee where id =#{param1} and name = #{param2}
</select>

 

2.3:用@param指定参数(推荐)

为参数使用 @Param 起一个名字, MyBatis 就会将这些参数封装进 map 中, key 就是我们自己指定的 名字
方法:
public Employee getEmployee2(@Param("id") Integer id, @Param("name") String name);

sql映射文件:

<select id="getEmployee2" resultType="com.wkl.bean.Employee">
    select * from t_employee where id =#{id} and name = #{name}
</select>
 

2.4:传入pojo(javabean)

当这些参数属于我们业务 POJO 时,我们直接传递 POJO,sql取值就是#{pojo的参数名}
方法名:
public Employee getEmployee3(Employee ee);

sql映射:

<select id="getEmployee3" resultType="com.wkl.bean.Employee">
    select * from t_employee where id =#{id} and name = #{name}
</select>

2.5:传入map

我们也可以封装多个参数为 map ,直接传递;这样取值的时候就是#{我们自定义的key}

2.6:传入混合参数

public Employee getEmployee4(@Param("id")Integer id,String name, Employee ee);

Integer id --->#{id}

name ---->#{param2}

Employee ee (取这里面的name)---->#{param3.name}

3:参数处理---设定参数的类型和$/#取值

1:参数也可以指定一个特殊的数据类型

<select id="getEmployee" resultType="com.wkl.bean.Employee">
    select * from t_employee where id =#{id,jdbcType=numeric}
</select>
参数位置支持的属性
javaType jdbcType mode numericScale

   resultMaptypeHandlerjdbcTypeNameexpression

实际上通常被设置的是  可能为空的列名指定 jdbcType

实际上通常被设置的是  可能为空的列名指定 jdbcType

2:#{属性名}和${属性名}的区别

1:#{属性名}支持参数预编译,参数位置用?代替;参数都数预编译设置进去的,安全,不会有sql注入

<select id="getEmployee3" resultType="com.wkl.bean.Employee">
    select * from t_employee where id =#{id} and name = #{name}
</select>

 

2:${属性名}不支持参数预编译,而是直接和sql'进行拼串;不安全;但是在表名;字段名等不支持参数预编译的地方会很方便

<select id="getEmployee2" resultType="com.wkl.bean.Employee">
    select * from ${tablename} where id =#{id} and name = #{name}
</select>

 

 

4: 查询返回集合list

方法:

public List<Employee> getEmployeeALL();

sql映射:

<!--public List<Employee> getEmployeeALL();-->
<!--resultType,如果返回集合;里面写的是返回集合的元素的类型-->
<select id="getEmployeeALL" resultType="com.wkl.bean.Employee">
    select * from t_employee
</select>

5: 查询返回map

5.1:查询返回一个map

<!--public Map<String,Object> getEmployeeResultMap(Integer id);-->
<!--resultType直接写map就行;到时候封装的时候就会将数据库字段名作为key;数据库字段值作为value-->
<select id="getEmployeeResultMap" resultType="map">
    select * from t_employee where id = #{id}
</select>

 

5.2:查询返回多个map

 方法:

/*必须指定那个字段作为主键;否则mybatis无法去对应*/
@MapKey("id")
public Map<Integer,Employee> getEmployeeAllResultMap();

sql映射文件:

<!--public Map<Integer,Employee> getEmployeeAllResultMap();-->
<select id="getEmployeeAllResultMap" resultType="com.wkl.bean.Employee">
    select * from t_employee
</select> 
 

6:resultMap---自定义封装结果集

6.1:mybait封装结果集时会按照列名和属性名一一对应,如果对应不上就为null;

表:

javabean

sql映射文件:

<!--public Cat getCat(Integer id);-->
<select id="getCat" resultType="com.wkl.bean.Cat">
    select * from t_cat where id = #{id}
</select>

结果:

6.2:自定义resultMap封装结果集

sql映射:

<!--public Cat getCat(Integer id);-->
    <!--想要使用自定义的结果集;那么就将resultType换成resultMap-->
    <select id="getCat" resultMap="mycat">
        select * from t_cat where id = #{id}
    </select>

    <!--
        id:唯一标识
        type:指定为那个javabean封装结果集,全类名
    -->
    <resultMap id="mycat" type="com.wkl.bean.Cat">
        <!--指定主键的对应规则
            column="id" :指定那一列是主键列
            property="id" :指定cat的那个属性封装id的这一列数据
        -->
        <id property="id" column="id"></id>

        <!--
            普通列;字段规则一样
        -->
        <result property="name" column="cname"></result>
        <result property="age" column="cage"></result>
    </resultMap>

结果:

6.3:封装复杂类型的对象(即对象里包含对象);

6.3.1:运用级联属性封装

javabean;

sql映射文件:

结果:

6.3.2:运用association标签定义对象的封装规则

sql映射文件

<!--public Cat getCat1(Integer id);-->
<select id="getCat1" resultMap="mycat2">
    select c.id as cid,c.cname,c.cage,c.person,e.id as eid,e.name,e.email from t_cat c
        LEFT JOIN t_employee e on c.person = e.id
        where c.id = #{id}
</select>
<resultMap id="mycat2" type="com.wkl.bean.Cat">
    <id property="id" column="cid"></id>
    <result property="name" column="cname"></result>
    <result property="age" column="cage"></result>
    <!--接下来的属性是一个对象,自定义这个对象的封装规则,使用association表示联合一个对象
        javaType表示指定这个属性的类型
    -->
    <association property="employee" javaType="com.wkl.bean.Employee">
        <id property="id" column="eid"></id>
        <result property="name" column="name"></result>
        <result property="email" column="email"></result>
    </association>
</resultMap>

6.4:查询对象中的封装集合-Collection

表关系:一个人有多个猫

javabean:

sql映射文件:

<!--public Employee getEmployeeCats(Integer id);-->
<select id="getEmployeeCats" resultMap="mycat3">
    select c.id as cid,c.cname,c.cage,c.person,e.id as eid,e.name,e.email from t_cat c
        LEFT JOIN t_employee e on c.person = e.id
        where e.id = #{id}
</select>
<resultMap id="mycat3" type="com.wkl.bean.Employee">
    <id property="id" column="eid"></id>
    <result property="name" column="name"></result>
    <result property="email" column="email"></result>
    <!--collection定义集合元素的封装
        property:指定那个属性是几个元素
        ofType:指定几个元素里面的封装规则
    -->
    <collection property="cats" ofType="com.wkl.bean.Cat">
        <id property="id" column="cid"></id>
        <result property="name" column="cname"></result>
        <result property="age" column="cage"></result>
    </collection>
</resultMap>

结果:

7:分步查询和延迟加载(不推荐)

7.1:分部查询

目的:就是将复杂的链接查询变成多个简单的查询;然后用前一个的结果集给第二个查询做参数

7.1.1:association-分段查询

说明:一个猫有一个主人;

sql映射:

这是另一个方法;专门利用人员id查询人员信息

<!--public Employee getEmployee(Integer id);-->
<select id="getEmployee" resultType="com.wkl.bean.Employee">
    select * from t_employee where id =#{id}
</select>
查询猫的信息;因为猫拥有一个主人,所以在association中利用分部查询进行主人的信息;
<!--public Cat getCat2(Integer id);-->
<select id="getCat2" resultMap="myassciation">
    select * from t_cat where id = #{id}
</select>
<resultMap id="myassciation" type="com.wkl.bean.Cat">
    <id property="id" column="id"></id>
    <result property="name" column="cname"></result>
    <result property="age" column="cage"></result>
    <!--告诉mybatis自己去查主人的信息
        select = "执行一个查询猫主人的唯一标识,mybatis将自动调用指定的sql将employee查出来";
        com.wkl.dao.EmployeeDao.getEmployee:需要传入人员id
        column:指定那一列的数据值传过去
    -->
    <association property="employee" select="com.wkl.dao.EmployeeDao.getEmployee"
                  column="person"></association>
</resultMap>

结果;

 

7.1.2:Collection--分段查询 

<!--public Employee getEmployee5(Integer id);-->
<select id="getEmployee5" resultMap="hahah">
    select * from t_employee where id = #{id}
</select>

<resultMap id="hahah" type="com.wkl.dao.EmployeeDao">
    <id property="id" column="name"></id>
    <result property="name" column="name"></result>
    <result property="email" column="email"></result>
    <!--通过主人查猫-->
    <collection property="cats" select="com.wkl.dao.CatDao.getCat"
                column="id"></collection>
</resultMap>
分步查询 的时候通过 column 指定,将对应的列的数据传递过去,我们有时需要传递多列数据
使用column= {key1=column1,key2=column2…} 的形式 

7.2:延迟加载

当猫对象有一个属性是Employee类;那么如果只需要查询猫名字的时候,在分步查询时不需要mybatis将猫主人信息查出来;这就是延迟加载

<!--重要的配置-->
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings> 

8:动态sql

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

8.1:if

<!--根据传入的对象,加入employee中某属性有值,就按照该属性取值-->
<!--public Employee getEmployeeByCondition(Employee ee);-->
<select id="getEmployeeByCondition" resultMap="employeeMap">
     select * from t_employee where 1=1
     /*test="" 编写判断条件
        id!=null取出javabean中的id属性值*/
      <if test="id!=null">
           and id > #{id}
      </if>
        /*ognl表达式,第一个name是数据库字段,第二个是传入的javabean的属性*/
      <if test="name!='' and name!=null">
           and name like #{name}
      </if>
</select>

8.2:where

where标签可以自动的为我们减去不需要的and链接符合增加where判断关键字

<!--根据传入的对象,加入employee中某属性有值,就按照该属性取值-->
<!--public Employee getEmployeeByCondition(Employee ee);-->
<select id="getEmployeeByCondition" resultMap="employeeMap">
     select * from t_employee
     <!--test="" 编写判断条件
        id!=null取出javabean中的id属性值-->
      <where>
          <if test="id!=null">
              and id > #{id}
          </if>
          <!--ognl表达式,第一个name是数据库字段,第二个是传入的javabean的属性-->
          <if test="name!='' and name!=null">
              and name like #{name}
          </if>
      </where>
</select>

8.3:trim标签

 

<!--prefix="" 前缀;为我们的sql整体填一个前缀
prefixOverrides="" 去除整体字符前边多余的前缀
suffix="" 后缀;为sql整体加一个后缀
suffixOverrides="" 去除整体字符后边多余的后缀-->
<trim prefix="where" prefixOverrides="and" suffix="" suffixOverrides="">
    <if test="id!=null">
        and id > #{id}
    </if>
    <!--ognl表达式,第一个name是数据库字段,第二个是传入的javabean的属性-->
    <if test="name!='' and name!=null">
        and name like #{name}
    </if>
</trim>

8.4:foreach

动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候
<!--public List<Employee> getEmployeeByIds(@Param("ids") List ids);-->
<select id="getEmployeeByIds" resultMap="employeeMap">
    select * from t_employee where id in
    <!--
        collection="ids" :标识遍历的集合
        close="":以什么结束;
        open="":以什么开始
        index="i":索引
            如果遍历的是一个list:
                index:指定当前的变量保存了当前的索引
                item:保存当前遍历的变量的值
            如果遍历的是一个map:
                index:指定的变量就是保存了当前遍历的元素的key;
                item:就是保存当前遍历元素的value
         item="变量名":每次便利店额元素的值;
         separator:每次遍历的分隔符
    -->
    <foreach collection="ids" close=")" item="id" open="(" separator=",">
        #{id}
    </foreach>
</select>

8.5:choose分支选择

相当于if---elase

<!--public List<Employee> getEmployeeByChoose(Employee ee);-->
<select id="getEmployeeByChoose" resultMap="employeeMap">
    select * from t_employee
    <where>
        <choose>
            <when test="id!=null">
                id = #{id}
            </when>
            <when test="name!=null and !name.equals(&quot;&quot;)">
                name =#{name}
            </when>
            <otherwise>
                1=1
            </otherwise>
        </choose>
    </where>
</select>

8.6:set标签动态修改

<!--public List<Employee> getEmployeeByIds(@Param("ids") List ids);-->
<update id="updateEmployee">
    update t_employee
    <!--set标签可以动态的将修改的语句最后的逗号去掉-->
    <set>
        <if test="name!='' and name!=null">
            name=#{name},
        </if>
        <if test="email!='' and email!=null">
            email = #{email},
        </if>
    </set>
    <where>
        id = #{id}
    </where>
</update>

8.7:mybatis的ognl表达式以及_parameter参数和_databaseId参数

OGNL Object Graph Navigation Language 对象图导航语言,这是一种强大表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的ELSpEL

 

访问对象属性:  person.name

调用方法:  person.getName()

调用静态属性/方法:  @java.lang.Math@PI 

  @java.util.UUID@randomUUID()

调用构造方法:  new com.atguigu.bean.Person(‘admin’).name

运算符:    +,-*,/,%

逻辑运算符:  in,not in,>,>=,<,<=,==,!=

    注意:xml中特殊符号如”,>,<等这些都需要使用转义字符

访问集合属性:

 

类型

伪属性

伪属性对应的 Java 方法

ListSetMap

sizeisEmpty

List/Set/Map.size(),List/Set/Map.isEmpty()

ListSet

iterator

List.iterator()Set.iterator()

Map

keysvalues

Map.keySet()Map.values()

Iterator

nexthasNext

Iterator.next()Iterator.hasNext()

_parameter:代表传入的参数;

         传入单个参数;_parameter就代表这个参数

          传入多个参数:_parameter就代表多个参数集合起来的map

_databaseId:代表当前环境

           这样就可以根据不同的数据库厂商构建特定的语句

 

 

8.8:sql标签,可重用的标签

 

<!--提取可重用的sql-->
<sql id="selectsql">
    select * from t_employee
</sql>

         

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苍煜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值