Mybatis(一)基础使用

Mybatis 基本应用

框架简介

三层架构

  • 软件开发常用的架构是三层架构,之所以流行是因为有着清晰的任务划分。一般包括以下三层:
    • 持久层:主要完成与数据库相关的操作,即对数据库的增删改查。
    • 因为数据库访问的对象一般称为Data Access Object(简称DAO),所以有人把持久层叫做DAO层。
    • 业务层:主要根据功能需求完成业务逻辑的定义和实现。 因为它主要是为上层提供服务的,所以有人把业务层叫做Service层或Business层。
    • 表现层:主要完成与最终软件使用用户的交互,需要有交互界面(UI)。因此,有人把表现层称之为web层或View层。
  • 三层架构之间调用关系为:表现层调用业务层,业务层调用持久层。
  • 各层之间必然要进行数据交互,我们一般使用java实体对象来传递数据。

Mybatis简介

  • MyBatis是一个优秀的基于ORM的半自动轻量级持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
  • mybatis 历史
    • MyBatis 本是apache的一个开源项目iBatis, 2010年6月这个项目由apache software foundation 迁移到了google code,随着开发团队转投到GoogleCode旗下,iBatis正式改名为MyBatis ,代码于2013年11月迁移到Github
    • Github地址:https://github.com/mybatis/mybatis-3/

Mybatis快速入门

MyBatis开发步骤 人狠话不多先上代码

环境搭建
   <!--maven导入依赖 驱动就不写了-->    
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
编写MyBatis核心文件
  • <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <!--加载properties文件-->
        <properties resource="jdbc.properties"></properties>
    
        <!--设置别名-->
        <typeAliases>
            <!--方式一:给单个实体起别名-->
           <!-- <typeAlias type="com.lagou.domain.User" alias="user"></typeAlias>-->
            <!--方式二:批量起别名 别名就是类名,且不区分大小写-->
            <package name="com.lagou.domain"/>
    
        </typeAliases>
    
    
        <!--environments: 运行环境 可以配置多个 environment-->
        <environments default="development">
            <environment id="development">
                    <!--当前的事务事务管理器是JDBC-->
                <transactionManager type="JDBC"></transactionManager>
                    <!--数据源信息 POOLED:使用mybatis的连接池 UNPOOLED就是不使用连接池-->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
    
        <!--引入映射配置文件-->
        <mappers>
            <mapper resource="mapper/UserMapper.xml"></mapper>
        </mappers>
    
    </configuration>
    
编写mapper映射
 <mapper namespace="userMapper">
      <!--namespace : 命名空间:与id属性共同构成唯一标识 namespace.id: user.findAll
          resultType: 返回结果类型(自动映射封装):要封装的实体的全路径
      -->
  
      <!-- 查询所有 -->
      <select id="findAll" resultType="uSeR">
          select * from user
      </select>
  
      <!--新增用户-->
      <!--#{} : mybatis中的占位符,等同于JDBC中的?
          parameterType :指定接收到的参数类型 -->
      <insert id="saveUser" parameterType="user">
          insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
      </insert>
  
  
      <!--更新用户-->
      <update id="updateUser" parameterType="user">
          update user set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address} where id = #{id}
      </update>
  
  
      <!--删除用户 java.lang.Integer-->
      <delete id="deleteUser" parameterType="int">
          delete from user where id = #{abc}
      </delete>
  </mapper>

MyBatis常用配置解析

environments标签
- 数据库环境的配置,支持多环境配置
-  其中,事务管理器(transactionManager)类型有两种: 
    -  JDBC: 这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。 
    -  MANAGED: 这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。 例如:mybatis与spring整合后,事务交给spring容器管理。
- 其中,数据源(dataSource)常用类型有三种: 
    - UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。 
    - POOLED: 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。 
    - JNDI : 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据 源,然后放置一个 JNDI 上下文的数据源引用
properties标签

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的 properties:
在这里插入图片描述

typeAliases标签
- 类型别名是为 Java 类型设置一个短的名字。
- 为了简化映射文件 Java 类型设置,mybatis框架为我们设置好的一些常用的类型的别名:

- 原来的类型名称配置如下:

- 配置typeAliases,为com.lagou.domain.User定义别名为user:
- 
        <!--设置别名-->
        <typeAliases>
            <!--方式一:给单个实体起别名-->
           <!-- <typeAlias type="com.lagou.domain.User" alias="user"></typeAlias>-->
            <!--方式二:批量起别名 别名就是类名,且不区分大小写-->
            <package name="com.lagou.domain"/>
    
        </typeAliases>
mappers标签
 - 该标签的作用是加载映射的,加载方式有如下几种:
- 
         使用相对于类路径的资源引用,例如: 
        <mapper resource="org/mybatis/builder/userMapper.xml"/> 
        使用完全限定资源定位符(URL),例如:
       <mapper url="file:///var/mappers/userMapper.xml"/> 
         《下面两种mapper代理开发中使用:暂时了解》 
        使用映射器接口实现类的完全限定类名,例如
        <mapper class="org.mybatis.builder.userMapper"/>
        将包内的映射器接口实现全部注册为映射器,例如: 
        <package name="org.mybatis.builder"/>  
其他标签就不多说了去官方看

Mybatis高级查询

ResutlMap属性

  • 建立对象关系映射

    • resultType 如果实体的属性名与表中字段名一致,将查询结果自动封装到实体类中
    • ResutlMap 如果实体的属性名与表中字段名不一致,可以使用ResutlMap实现手动封装到实体类中
          <resultMap id="orderMap" type="com.lagou.domain.Orders">
              <id property="id" column="id"/>
              <result property="ordertime" column="ordertime"/>
              <result property="total" column="total"/>
              <result property="uid" column="uid"/>
          </resultMap>
      
          <select id="findAllWithUser" resultMap="orderMap">
              SELECT * FROM orders
          </select>
    

多条件查询(三种)

方式一

  • 使用 #{arg0}-#{argn} 或者 #{param1}-#{paramn} 获取参数
  •    <!--多条件查询:方式一-->
    
      <select id="findByIdAndUsername1" resultMap="userResultMap" >
          <!-- select * from user where id = #{arg0} and username = #{arg1}-->
          select * from user where id = #{param1} and username = #{param2}
    
      </select>
    

方式二

  • 使用注解,引入 @Param() 注解获取参数
  •    /*
         多条件查询方式二
      */
      public List<User> findByIdAndUsername2(@Param("id") int id, @Param("username") String username);
      <!--多条件查询:方式二-->
    
      <select id="findByIdAndUsername2" resultMap="userResultMap" >
          select * from user where id = #{id} and username = #{username}
      </select>
    

方式三(推荐)

  • 使用pojo对象传递参数
  •    /*
            多条件查询方式三
         */
          public List<User> findByIdAndUsername3(User user);
            <!--多条件查询:方式三-->
      
          <select id="findByIdAndUsername3" resultMap="userResultMap" parameterType="com.lagou.domain.User">
              select * from user where id = #{id} and username = #{usernameabc}
      
          </select>
    

模糊查询

    <!--模糊查询:方式一-->
    username传值要带%号
    <select id="findByUsername" resultMap="userResultMap" parameterType="string">
        <!-- #{}在mybatis中是占位符,引用参数值的时候会自动添加单引号 -->
        select * from user where username like #{username}
    </select>
    <!--模糊查询:方式二-->
    <select id="findByUsername2" resultMap="userResultMap" parameterType="string">
        <!--parameterType是基本数据类型或者String的时候,${}里面的值只能写value
            ${}: sql原样拼接 有注入风险
        -->
        select * from user where username like '${value}'
    </select>
  • ${} 与 #{} 区别【笔试题】
    • #{} :表示一个占位符号
      • 通过 #{} 可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换
      • #{}可以有效防止sql注入。
      • #{} 可以接收简单类型值或pojo属性值。
      • 如果parameterType传输单个简单类型值, #{} 括号中名称随便写。
    • ${} :表示拼接sql串
      • 通过 ${} 可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,会出现sql注入问题。
      • ${} 可以接收简单类型值或pojo属性值。
      • 如果parameterType传输单个简单类型值, ${} 括号中只能是value。
        • 补充:TextSqlNode.java 源码可以证明

Mybatis映射文件深入

返回主键

  • 我们很多时候有这种需求,向数据库插入一条记录后,希望能立即拿到这条记录在数据库中的主键值

  •   <!--添加用户:获取返回主键:方式一-->
          <!--
              useGeneratedKeys: 声明返回主键
              keyProperty:把返回主键的值,封装到实体中的那个属性上
          -->
          <insert id="saveUser" parameterType="user" useGeneratedKeys="true" keyProperty="id">
              insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
          </insert>
      
      
          <!--添加用户:获取返回主键:方式二-->
      
          <insert id="saveUser2" parameterType="user" >
      
              <!--
                  selectKey : 适用范围更广,支持所有类型的数据库
                      order="AFTER"  : 设置在sql语句执行前(后),执行此语句
                      keyColumn="id" : 指定主键对应列名
                      keyProperty="id":把返回主键的值,封装到实体中的那个属性上
                       resultType="int":指定主键类型
              -->
              <selectKey order="AFTER" keyColumn="id" keyProperty="id" resultType="int">
                  SELECT LAST_INSERT_ID();
              </selectKey>
              insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
          </insert>
    
  • 主键返回是直接在 实体对象中

动态SQL

  • 当我们要根据不同的条件,来执行不同的sql语句的时候,需要用到动态sql

动态 SQL 之

 <!-- 动态sql之if : 多条件查询-->
    <select id="findByIdAndUsernameIf" parameterType="user" resultType="com.lagou.domain.User">
        select * from user
        <!-- test里面写的就是表达式
            <where>: 相当于where 1= 1,但是如果没有条件的话,不会拼接上where关键字
        -->
        <where>
           <if test="id != null">
                and id = #{id}
           </if>
           <if test="username !=null">
                and username = #{username}
           </if>
        </where>

    </select>

动态 SQL 之

    <!--动态sql之set : 动态更新-->
    <update id="updateIf" parameterType="user">
        update user
        <!--<set> : 在更新的时候,会自动添加set关键字,还会去掉最后一个条件的逗号 -->
        <set>
            <if test="username != null">
                username = #{username},
            </if>
            <if test="birthday != null">
                birthday = #{birthday},
            </if>
            <if test="sex != null">
                sex = #{sex},
            </if>
            <if test="address != null">
                address = #{address},
            </if>

        </set>
            where id = #{id}
    </update>


    <sql id="selectUser">
        select * from user
    </sql>

动态 SQL 之

    <!--动态sql的foreach标签:多值查询:根据多个id值查询用户-->
    <select id="findByList" parameterType="list" resultType="user">
        <include refid="selectUser"/>
        <where>
            <!--
                collection : 代表要遍历的集合元素,通常写collection或者list
                open : 代表语句的开始部分
                close : 代表语句的结束部分
                item : 代表遍历结合中的每个元素,生成的变量名
                separator: 分隔符
             -->
            <foreach collection="collection" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>

    </select>


    <!--动态sql的foreach标签:多值查询:根据多个id值查询用户-->
    <select id="findByArray" parameterType="int" resultType="user">
        <include refid="selectUser"/>
        <where>
            <!--
                collection : 代表要遍历的集合元素,通常写collection或者list
                open : 代表语句的开始部分
                close : 代表语句的结束部分
                item : 代表遍历结合中的每个元素,生成的变量名
                separator: 分隔符
             -->
            <foreach collection="array" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>

    </select>

SQL片段

  • 映射文件中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
  •   <sql id="selectUser">
      select * from user
      </sql>
      <!--动态sql的foreach标签:多值查询:根据多个id值查询用户-->
      <select id="findByList" parameterType="list" resultType="user">
          <include refid="selectUser"/> 包含sql片段
          <where>
              <!--
                  collection : 代表要遍历的集合元素,通常写collection或者list
                  open : 代表语句的开始部分
                  close : 代表语句的结束部分
                  item : 代表遍历结合中的每个元素,生成的变量名
                  separator: 分隔符
               -->
              <foreach collection="collection" open="id in (" close=")" item="id" separator=",">
                  #{id}
              </foreach>
          </where>
    
      </select>
    

知识小结

  • :查询
  • :插入
  • :修改
  • :删除
  • :返回主键
  • :where条件
  • :if判断
  • :for循环
  • :set设置
  • :sql片段抽取

Mybatis核心配置文件深入

plugins标签

  • MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
    • 开发步骤:
      • 导入通用PageHelper的坐标
      • 在mybatis核心配置文件中配置PageHelper插件
      • 测试分页数据获取
  •   maven pom.xml
     <!-- 分页助手 -->
      <dependency>
          <groupId>com.github.pagehelper</groupId>
          <artifactId>pagehelper</artifactId>
          <version>3.7.5</version>
      </dependency>
    
      <dependency>
          <groupId>com.github.jsqlparser</groupId>
          <artifactId>jsqlparser</artifactId>
          <version>0.9.1</version>
      </dependency>
      
     sqlconfig.xml
      <plugins>
          <plugin interceptor="com.github.pagehelper.PageHelper">
    
              <!--dialect: 指定方言 limit-->
              <property name="dialect" value="mysql"/>
          </plugin>
      </plugins>
      
      // 设置分页参数
      // 参数1: 当前页
      // 参数2: 每页显示的条数
      PageHelper.startPage(1,2);
    
      List<User> users = mapper.findAllResultMap();
      for (User user : users) {
          System.out.println(user);
      }
    
      // 获取分页相关的其他参数
      PageInfo<User> pageInfo = new PageInfo<User>(users);
      
      System.out.println("总条数:"+pageInfo.getTotal()); System.out.println("总页数:"+pageInfo.getPages()); System.out.println("当前页:"+pageInfo.getPageNum()); System.out.println("每页显示长度:"+pageInfo.getPageSize()); System.out.println("是否第一页:"+pageInfo.isIsFirstPage()); System.out.println("是否最后一页:"+pageInfo.isIsLastPage())
    

知识小结

  • MyBatis核心配置文件常用标签:
    • properties标签:该标签可以加载外部的properties文件
    • typeAliases标签:设置类型别名
    • environments标签:数据源环境配置标签
    • plugins标签:配置MyBatis的插件

Mybatis多表查询

一对一(多对一)

    <!--一对一关联查询:查询所有订单,与此同时还要查询出每个订单所属的用户信息-->

    <resultMap id="orderMap" type="com.lagou.domain.Orders">
        <id property="id" column="id"/> 绑定主键
        <result property="ordertime" column="ordertime"/>
        <result property="total" column="total"/>
        <result property="uid" column="uid"/>


        <!--
            association : 在进行一对一关联查询配置时,使用association标签进行关联
                property="user" :要封装实体的属性名
                javaType="com.lagou.domain.User" 要封装的实体的属性类型
        -->
        <association property="user" javaType="com.lagou.domain.User">
            <id property="id" column="uid"></id> 绑定主键 传值uid
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>

        </association>
    </resultMap>

    <select id="findAllWithUser" resultMap="orderMap">
        SELECT * FROM orders o LEFT JOIN USER u ON o.uid = u.id
    </select>

一对多

<!--一对多关联查询:查询所有的用户,同时还要查询出每个用户所关联的订单信息-->

<resultMap id="userMap" type="com.lagou.domain.User">
    <id property="id" column="id"></id>
    <result property="username" column="username"></result>
    <result property="birthday" column="birthday"></result>
    <result property="sex" column="sex"></result>
    <result property="address" column="address"></result>


    <!--
        collection : 一对多使用collection标签进行关联
        property: User实体类中对应的成员变量
        ofType:封装集合的泛型类型
    -->
    <collection property="ordersList" ofType="com.lagou.domain.Orders">
        <id property="id" column="oid"></id>
        <result property="ordertime" column="ordertime"/>
        <result property="total" column="total"/>
        <result property="uid" column="uid"/>
    </collection>

</resultMap>


<select id="findAllWithOrder"  resultMap="userMap">
   SELECT u.*,o.id oid,o.ordertime,o.total,o.uid FROM orders o RIGHT JOIN USER u ON o.uid = u.id
</select>

多对多

<!--多对多关联查询:查询所有的用户,同时还要查询出每个用户所关联的角色信息-->

<resultMap id="userRoleMap" type="user">
    <id property="id" column="id"/>
    <result property="username" column="username"></result>
    <result property="birthday" column="birthday"></result>
    <result property="sex" column="sex"></result>
    <result property="address" column="address"></result>

    <collection property="roleList" ofType="role">
        <id column="rid" property="id"></id>
        <result column="rolename" property="rolename"></result>
        <result column="roleDesc" property="roleDesc"></result>
     </collection>

</resultMap>

<select id="findAllWithRole" resultMap="userRoleMap">
    SELECT u.*,r.id rid,r.rolename,r.roleDesc FROM USER u LEFT JOIN sys_user_role ur ON ur.userid = u.id
	     LEFT JOIN sys_role r ON ur.roleid = r.id
</select>

小结

  • 多对一(一对一)配置:使用+做配置 *
  • 一对多配置:使用+做配置 *
  • 多对多配置:使用+做配置 *
  • 多对多的配置跟一对多很相似,难度在于SQL语句的编写

MyBatis嵌套查询

  • 嵌套查询就是将原来多表查询中的联合查询语句拆成单个表的查询,再使用mybatis的语法嵌套在一起。
  •    联合查询
      SELECT * FROM orders o LEFT JOIN USER u ON o.`uid`=u.`id`; 
       嵌套查询 
       先查询订单 SELECT * FROM orders 
      再根据订单uid外键,查询用户 SELECT * FROM `user` WHERE id = #{根据订单查询的uid}
       最后使用mybatis,将以上二步嵌套起来
    

一对一嵌套查询

    <resultMap id="orderMap2" type="com.lagou.domain.Orders">
    <id property="id" column="id"/>
    <result property="ordertime" column="ordertime"/>
    <result property="total" column="total"/>
    <result property="uid" column="uid"/>

    <!--问题:1.怎么去执行第二条sql , 2.如何执行第二条sql的时候,把uid作为参数进行传递
    column:uid
    property:实体类对应成员变量
    javaType 封装集合的泛型
    fetchType 是否懒加载 eager立刻加载  lazy 懒加载
    select查询语句
    -->
    <association property="user" javaType="com.lagou.domain.User"
                 select="com.lagou.mapper.UserMapper.findById" column="uid" fetchType="eager"/>



    </resultMap>

    <!--一对一嵌套查询-->
    <select id="findAllWithUser2" resultMap="orderMap2">
        SELECT * FROM orders
    </select>
      
      <!--根据id查询用户
        useCache="true" 代表当前这个statement是使用二级缓存
    -->
    <select id="findById" resultType="com.lagou.domain.User" parameterType="int" useCache="true">
        SELECT * FROM user WHERE id = #{id}
    </select>

一对多嵌套查询

    <!--一对多嵌套查询:查询所有的用户,同时还要查询出每个用户所关联的订单信息-->

    <resultMap id="userOrderMap" type="com.lagou.domain.User">
        <id property="id" column="id"/>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>


        <!--fetchType="lazy" : 延迟加载策略
            fetchType="eager": 立即加载策略
        -->
        <collection property="ordersList" ofType="com.lagou.domain.Orders" column="id"
                    select="com.lagou.mapper.OrderMapper.findByUid" ></collection>

    </resultMap>

    <select id="findAllWithOrder2" resultMap="userOrderMap">
        SELECT * FROM USER
    </select>
    
    <select id="findByUid" parameterType="int" resultType="com.lagou.domain.Orders">
    SELECT * FROM orders WHERE uid = #{uid}
     </select>

多对多嵌套查询

    <resultMap id="userRoleMap2" type="com.lagou.domain.User">
        <id property="id" column="id"/>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>

        <collection property="roleList" ofType="com.lagou.domain.Role" column="id" select="com.lagou.mapper.RoleMapper.findByUid"></collection>
    </resultMap>

    <!--多对多嵌套查询:查询所有的用户,同时还要查询出每个用户所关联的角色信息-->
    <select id="findAllWithRole2" resultMap="userRoleMap2">
        SELECT * FROM USER
    </select>
    
    <select id="findByUid" resultType="com.lagou.domain.Role" parameterType="int">
    SELECT * FROM sys_role r INNER JOIN sys_user_role ur ON ur.roleid = r.id
		WHERE ur.userid = #{uid}
    </select>

小结

  • 一对一配置:使用+做配置,通过column条件,执行select查询
  • 一对多配置:使用+做配置,通过column条件,执行select查询
  • 多对多配置:使用+做配置,通过column条件,执行select查询
  • 优点:简化多表查询操作 缺点:执行多次sql语句,浪费数据库性能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值