MyBatis基础笔记(非常全)

本文详细介绍MyBatis环境搭建过程,包括配置文件设置、数据库连接池应用、动态SQL实现方式等,并介绍了MyBatis的基本使用方法,如增删改查操作、结果映射等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境搭建

  1. 导入各种jar
  2. src下新建全局配置文件(编写JDBC四个变量)
    1. 没有名称和地址要求
    2. 在全局配置文件中引入DTDschema
      1. 若导入dtd之后没有提示
      window-->preference-->XML-->XML catalog-->add
      //添加dtd
      
    3. 全局配置文件内容
    <?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>
        <!-- default 引用 environment 的 id,当前所使用的环境 -->
            <environments default="default">
        <!-- 声明可以使用的环境 -->
                <environment id="default">
        <!-- 使用原生 JDBC 事务 -->
                    <transactionManager type="JDBC"></transactionManager>
                    <dataSource type="POOLED">
                        <property name="driver" value="com.mysql.jdbc.Driver"/>
                        <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                        <property name="username" value="root"/>
                        <property name="password" value="smallming"/>
                    </dataSource>
                </environment>
            </environments>
        </configuration>
    
  3. 新建以mapper结尾的包,在包下新建:实体类名+Mapper.xml
    1. 文件作用:编写需要执行的SQL命令
    2. xml文件理解成实体类
    3. xml文件内容
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- namesapce:理解成实现类的全路径(包名+类名) -->
    <mapper namespace="a.b" >
    <!-- id:方法名
    parameterType:定义参数类型
    resultType:返回值类型. 如果方法返回值是 list,在 resultType 中写 List 的泛型,
    因为 mybatis对 jdbc 封装,一行一行读取数据
    -->
        <select id="selAll" resultType="com.bjsxt.pojo.Flower">
            select * from flower
        </select>
    </mapper>
    
  4. 测试结果(只有在单独使用mybatis时使用,跟ssm整合时,下面代码不用写)
InputStream is = Resources.getResourceAsStream("myabtis.xml");
//使用工厂设计模式
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//生产 SqlSession
SqlSession session=factory.openSession();
List<Flower> list = session.selectList("a.b.selAll");
for (Flower flower : list) {
    System.out.println(flower.toString());
}
session.close();

环境搭建详解

  1. 全局配置文件中内容
    1. <transactionManager/>type 属性可取值
      1. JDBC,事务管理使用 JDBC 原生事务管理方式
      2. MANAGED 把事务管理转交给其他容器.原生 JDBC事务setAutoMapping(false);
    2. <dataSouce/>type属性
      1. POOLED 使用数据库连接池
      2. UNPOOLED 不实用数据库连接池,和直接使用 JDBC 一样
      3. JNDI :java 命名目录接口技术

数据库连接池

  1. 在内存中开辟一块空间,存放多个数据库连接对象.
  2. JDBC Tomcat Pool,直接由 tomcat 产生数据库连接池.
  3. 状态
    1. active 状态: 当前连接对象被应用程序使用中
    2. Idle 空闲状态: 等待应用程序使用
  4. 使用数据库连接池的目的
    1. 在高频率访问数据库时,使用数据库连接池可以降低服务器系
      统压力,提升程序运行效率.
      1. 小型项目不适用数据库连接池.
  5. 实现 JDBC tomcat Pool 的步骤.
    1. web 项目的 META-INF 中存放 context.xml,在 context.xml 编写数据库连接池相关属性
    <?xml version="1.0" encoding="UTF-8"?>
    <Context>
    <Resource 
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/ssm"
        username="root"
        password="smallming"
        maxActive="50"
        maxIdle="20"
        name="test"
        auth="Container"
        maxWait="10000"
        type="javax.sql.DataSource"
    />
    </Context>
    
    1. 把项目发布到tomcat中,数据库连接池就产生了
  6. 可以在java中使用jndi获取数据库连接池中对象
    1. Context: 上下文接口,context.xml文件对象类型
    2. 代码:
    Context cxt = new InitialContext();
    DataSource ds = (DataSource)
    cxt.lookup("java:comp/env/test");
    Connection conn = ds.getConnection();
    
    1. 当关闭连接对象时,把对象归还给数据库连接池,把状态改成Idle

三种查询方式

  1. selectList()返回值为List<resultType 属性控制>
    1. 适用于查询结果都需要遍历的需求
    List<Flower> list = session.selectList("a.b.selAll");
    for (Flower flower : list) {
        System.out.println(flower.toString());
    }
    
  2. selectOne()返回值为Object
    1. 适用于返回结果只是变量或一行数据时
    int count = session.selectOne("a.b.selById");
    System.out.println(count);
    
  3. selectMap() 返回值 Map
    1. 适用于需要在查询结果中通过某列的值取到这行数据的需求.
    2. Map<key,resultType 控制>
      Map<Object, Object> map = session.selectMap("a.b.c","name123");
      System.out.println(map);
      

注解

  1. 注解存在的意义:简化xml文件的开发
  2. 注解在servlet3.0规范之后大力推广的
  3. 注解前面的@XXX 表示引用一个@interface
    1. @interface 表示注解的声明
  4. 注解可以有属性,因为注解就是一个接口(类)
    1. 每次使用注解都要导包
  5. 注解的语法: @XXX(属性名 = 值)
  6. 值的分类
    1. 如果值是基本的数据类型或字符串:属性名=值
    2. 如果值是数组类型:属性名={值,值}
      1. 如果只有一个值可以省略大括号
    3. 如果值是类类型,属性名=@名称
  7. 如果注解只需要给一个属性赋值,且这个属性是默认属性,可以省略属性名

路径

  1. 编写路径为了告诉编译器如何找到其他资源.
  2. 路径分类
    1. 相对路径:从当前资源出发找到其他资源的过程
    2. 绝对路径: 从根目录(服务器根目录或项目根目录)出发找到其他资源的过程
      1. 标志: 只要以 / 开头的都是绝对路径
  3. 绝对路径:
    1. 如果是请求转发 / 表示项目根目录(WebContent)
    2. 其他重定向,<img/> <script/>,<style/>,location.href/都表示
      服务器根目录(tomcat/webapps 文件夹)
  4. 如果客户端请求的控制器,控制器转发到JSP后,jsp中如果使用相对
    路径,需要按照控制器的路径去找其他资源.
    1. 保险办法:使用绝对路径,可以防止上面的问题

Log4J

  1. apache推出的开源免费日志处理的类库
  2. 为什么需要日志:
    1. 在项目中编写System.out.println();输出到控制台,当项目发布到tomcat以后,没有控制台(在命令行界面能看见),不容易观察一些输出结果
    2. log4j作用,不仅能把内容输出到控制台,还能把内容输出到文件中,便于观察结果
  3. 使用步骤
    1. 导入log4j-xxx.jar
    2. src 下新建log4j.properties(路径和名称都不允许改变)
      1. ConversionPattern: 写表达式
      2. log4j.appender.appender.LOGFTLE.File:文件位置及名称(日志文件拓展名.log)
      log4j.rootCategory=DEBUG, CONSOLE ,LOGFILE //控制输出级别为info
      log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
      log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
      log4j.appender.CONSOLE.layout.ConversionPattern=%C %d{YYYY-MM-dd hh:mm:ss} %m %n
      log4j.appender.LOGFILE=org.apache.log4j.FileAppender
      log4j.appender.LOGFILE.File=E:/my.log
      log4j.appender.LOGFILE.Append=true
      log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
      log4j.appender.LOGFILE.layout.ConversionPattern=%C %m %L %n
      
  4. log4j输出级别
    1. fatal(致命错误) > error(错误) > warn(警告) > info(普通信息) > debug(调试信息)
    2. log4j.properties的第一行控制输出级别
  5. log4j输出目的地
    1. 在一行控制输出目的地
    log4j.rootCategory=DEBUG, CONSOLE ,LOGFILE
    //console对应文件中的log4j.appender.CONSOLE.*
    //logfile对应文件中的log4j.appender.LOGFILE.*
    
  6. pattern中常用几个表达式
    1. %C 包名+类名
    2. %d{YYYY-MM-dd HH:mm:ss} 时间
    3. %L 行号
    4. %m 信息
    5. %n 换行

标签

  1. mybatis全局配置文件中通过<settings>标签控制mybatis全局开关
  2. mybatis.xml中开启log4j
    1. 必须保证有log4j.jar
    2. src下有log4j.properties
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
  3. log4j中可以输出指定内容的日志(控制某个局部内容的日志级别)
    1. 命名级别(包级别):<mapper>namespace中除了最后一个是类名。例如namespace=”com.bjsxt.mapper.PeopleMapper,其中包级别为com.bjsxt.mapper ,需要在 log4j.propeties
      1. 先在总体级别调成 Error 不输出无用信息
      2. 在设置某个指定位置级别为DEBUG
      log4j.rootCategory=ERROR, CONSOLE ,LOGFILE
      
      log4j.logger.com.bjsxt.mapper.mapper = DEBUG
      
    2. 类级别
      1. namespace 属性值 ,namespace 类名
    3. 方法级别
      1. 使用 namespace 属性值+标签 id 属性值

parameterType 属性

  1. XXXMapper.xml<select><delect>等标签的parameterType可以控制参数类型
  2. SqlSessionselectList()selectOne()的第二个参数和 selectMap()的第三个参数都表示方法的参数
    1. 示例
    People p = session.selectOne("a.b.selById",1);
    System.out.println(p
    
    1. Mapper.xml 中可以通过#{}获取参数
      1. parameterType 控制参数类型
      2. #{}获取参数内容
        1. 使用索引,从 0 开始#{0}表示第一个参数
        2. 也可以使用#{param1}第一个参数
        3. 如果只有一个参数(基本数据类型String),mybatis#{}里面内容没有要求只要写内容即可
           <select id="selById" resultType="com.bjsxt.pojo.People" parameterType="int">
               select * from people where id=#{0}
           </select>
          
        4. 如果参数是对象#{属性名}
        5. 如果参数是 map写成#{key}
  3. #{}${} 的区别
    1. #{} 获取参数的内容支持索引获取,param1 获取指定位置参数, 并且 SQL 使用?占位符
    2. ${} 字符串拼接不使用?,默认找${内容}内容的get/set 方法,如果写数字,就是一个数字
  4. 如果在 xml 文件中出现 “<” , “>”,双引号 等特殊字符时可以使用
    XML文件转义标签(XML 自身的)**例如:
    1. <![CDATA[ 内容 ]]>
  5. mybatis 中实现 mysql 分页写法
    1. ?不允许在关键字前后进行数学运算,需要在代码中计算完成
      后传递到 mapper.xml
    2. java代码中计算
          //显示几个
          int pageSize = 2;
          //第几页
          int pageNumber= 2;
          //如果希望传递多个参数,可以使用对象或map
          mapMap<String,Object> map = new HashMap<>();
          map.put("pageSize", pageSize);
          //每一页开始的编号
          map.put("pageStart", pageSize*(pageNumber-1));
          //第二个参数传递了map给xml
          List<People> p =session.selectList("a.b.page",map);
      
      1. mapper.xml中的代码
            <select id="page" resultType="com.bjsxt.pojo.People" parameterType="map">
                select * from people limit #{pageStart},#{pageSize}
            </select>
        

typeAliases 别名

  1. 系统内置别名: 把类型全小写
  2. 给某个类起别名
    1. alias=“自定义”
      //给com.bjsxt.pojo.People起别名为peo
      <typeAliases>
          <typeAlias type="com.bjsxt.pojo.People"alias="peo"/>
      </typeAliase
      
    2. mapper.xmlpeo 引用 People
      <select id="page" resultType="peo" parameterType="map">
          select * from people limit #{pageStart},#{pageSize}
      </select>
      
  3. 直接给某个包下所有类起别名,别名即为类名,不区分大小写
    1. mybatis.xml 中配置
      <typeAliases>
          <package name="com.bjsxt.pojo" />
      </typeAliases>
      
    2. mapper.xml 中通过类名引用
      <select id="page" resultType="People" parameterType="map">
          select * from people limit #{pageStart},#{pageSize}
      </select>
      

Mybatis实现新增

  1. 概念
    1. 功能:从应用程序角度出发,软件具有哪些功能.
    2. 业务:完成功能时的逻辑.对应 Service 中一个方法
    3. 事务:从数据库角度出发,完成业务时需要执行的 SQL 集合,统
      称一个事务.
      1. 事务回滚:如果在一个事务中某个SQL 执行事务,希望回
        归到事务的原点,保证数据库数据的完整性.
  2. mybatis 中默认是关闭了JDBC的自动提交功能
    1. 每一个SqlSession默认都是不自动提交事务.
    2. session.commit()提交事务.
    3. openSession(true);自动提交.setAutoCommit(true);
  3. mybatis 底层是对JDBC的封装.
    1. JDBCexecuteUpdate()执行新增,删除,修改的 SQL.返回值 int, 表示受影响的行数.
    2. mybatis<insert> <delete> <update>标签没有 resultType 属性, 认为返回值都是 int
  4. openSession()Mybatis 会创建 SqlSession 时同时创建一个
    Transaction(事务对象),同时autoCommit 都为false
    1. 如果出现异常,应该 session.rollback()回滚事务
  5. 实现新增的步骤
    1. mapper.xml 中提供<insert>标签,标签没有返回值
      <insert id="ins" parameterType="People">
          insert into people values(default,#{name},#{age})
      </insert>
      
    2. 通过 session.insert()调用新增方法
      //传给xml文件一个p对象
      int index1 = session.insert("a.b.ins", p);
      if(index1>0){
          System.out.println("成功");
      }else{
          System.out.println("失败");
      }    
      

MyBatis实现修改

  1. mapper.xml 中提供<update>标签
    <update id="upd" parameterType="People">
        update people set name = #{name} where id = #{id}
    </update>
    
  2. 测试代码
        People peo = new People();
        peo.setId(3);
        peo.setName("王五");
        int index = session.update("a.b.upd", peo);
        if(index>0){
            System.out.println("成功");
        }else{
            System.out.println("失败");
        }
        //MyBatis默认不自动提交
        session.commit();
    

MyBatis实现删除

  1. mapper.xml 提供<delete>
    <delete id="del" parameterType="int">
        delete from people where id = #{0}
    </delete>
    
  2. 测试代码
        int del = session.delete("a.b.del",3);
        if(del>0){
            System.out.println("成功");
        }else{
            System.out.println("失败");
        }
        session.commit();
    

MyBatis 接口绑定方案及多参数传递

  1. 作用:实现创建一个接口后把mapper.xmlmybatis生成接口的实现类,通过调用接口对象就可以获取mapper.xml中编写的sql
  2. 后面mybatisspring整合时使用的是这个方案
  3. 实现步骤:
    1. 创建一个接口
      1. 接口包名和接口名与mapper.xml<mapper>namespace
        相同
      2. 接口中方法名和 mapper.xml 标签的 id 属性相同
    2. mybatis.xml 中使用<package>进行扫描接口和 mapper.xml
  4. 代码实现步骤:
    1. mybatis.xml<mappers>下使用<package>
      <mappers>
          <package name="com.xxx.mapper"/>
      </mappers>
      
    2. com.xxx.mapper 下新建接口
      public interface LogMapper {
          List<Log> selAll();
      }
      
    3. com.xxx.mapper新建一个 LogMapper.xml
      1. namespace 必须和接口全限定路径(包名+类名)一致
      2. id 值必须和接口中方法名相同
      3. 如果接口中方法为多个参数,可以省略 parameterType
      <mapper namespace="com.xxx.mapper.LogMapper">
          <select id="selAll" resultType="log">
              select * from log
          </select>
      </mapper>
      
  5. 多参数的实现方法
    1. 在接口中声明方法
    List<Log> selByAccInAccout(String accin,String accout);
    
    1. 在 mapper.xml 中添加
      1. #{}中使用 0,1,2param1,param2
      <!-- 当多参数时,不需要写 parameterType -->
      <select id="selByAccInAccout" resultType="log" >
          select * from log where accin=#{0} and accout=#{1}
      </select>
      
  6. 可以使用注解的方式
    1. 在接口中声明方法
    /**
    * mybatis 把参数转换为 map 了,其中@Param("key") 参数内
    容就是 map 的 value
    * @param accin123
    * @param accout3454235
    * @return
    */
    List<Log> selByAccInAccout(@Param("accin") String
    accin123,@Param("accout") String accout3454235);
    
    1. mapper.xml 中添加
      1. #{}里面写@Param(“内容”)参数中内容
      <!-- 当多参数时,不需要写 parameterType -->
      <select id="selByAccInAccout" resultType="log" >
          select * from log where accin=#{accin} and accout=#{accout}
      </select>
      

动态SQL

  1. 根据不同的条件需要执行不同的 SQL 命令.称为动态 SQL
  2. MyBatis 中动态 SQLmapper.xml中添加逻辑判断等.
  3. <If>使用
    <select id="selByAccinAccout" resultType="log">
            select * from log where 1=1
        <!-- OGNL 表达式,直接写 key 或对象的属性.不需要添加任何特字符号 -->
        <if test="accin!=null and accin!=''">
            and accin=#{accin}
        </if>
        <if test="accout!=null and accout!=''">
            and accout=#{accout}
        </if>
    </select>
    
  4. <where>
    1. 当编写 where 标签时,如果内容中第一个是 and 去掉第一个
      and
    2. 如果<where>中有内容会生成 where 关键字,如果没有内容不
      生成 where 关键字
    3. 使用示例
      1. 比直接使用<if>少写 where 1=1
      <select id="selByAccinAccout" resultType="log">
          select * from log
          <where>
              <if test="accin!=null and accin!=''">
                  and accin=#{accin}
              </if>
              <if test="accout!=null and accout!=''">
                  and accout=#{accout}
              </if>
          </where>
      </select>
      
  5. <choose> <when> <otherwise>
    1. 只有有一个成立,其他都不执行.
    2. 代码示例
      1. 如果 accinaccout 都不是 null或不是空生成的 sql中只有where accin=?(choose标签导致)
      <select id="selByAccinAccout" resultType="log">
          select * from log
          <where>
              <choose>
                  <when test="accin!=null and accin!=''">
                      and accin=#{accin}
                  </when>
                  <when test="accout!=null and accout!=''">
                      and accout=#{accout}
                  </when>
              </choose>
          </where>
      </select>
      
  6. <set>用在修改 SQLset 从句
    1. 作用:去掉最后一个逗号
    2. 作用:如果<set>里面有内容生成 set 关键字,没有就不生成
    3. 示例
      1. id=#{id} 目的防止<set>中没有内容,mybatis不生成 set 关键字,如果修改中没有 set 从句SQL 语法错误.
      <update id="upd" parameterType="log" >
          update log
          <set>
              id=#{id},
              <if test="accIn!=null and accIn!=''">
                  accin=#{accIn},
              </if>
              <if test="accOut!=null and accOut!=''">
                  accout=#{accOut},
              </if>
          </set>
          where id=#{id}
      </update>
      
  7. Trim标签
    1. prefix 在前面添加内容
    2. prefixOverrides 去掉前面内容
    3. suffix在后面添加内容
    4. suffixOverrieds 去掉后面内容
    5. 执行顺序:去掉内容后添加内容
    6. 代码示例(去掉最后一个逗号)
    <update id="upd" parameterType="log">
        update log
        <trim prefix="set" suffixOverrides=",">
            a=a,
        </trim>
        where id=100
    </update>
    
  8. <bind>
    1. 作用:给参数重新赋值
    2. 使用场景:
      1. 模糊查询
      2. 在原内容前或后添加内容
    3. 示例
    <select id="selByLog" parameterType="log" resultType="log">
        <bind name="accin" value="'%'+accin+'%'"/>
        #{money}
    </select>
    
  9. <foreach>标签
    1. 循环参数内容,还具备在内容的前后添加内容,还具备添加分
      隔符功能.
    2. 适用场景:in 查询中.批量新增中(mybatisforeach 效率比较低)
      1. 如果希望批量新增,SQL 命令
      insert into log VALUES (default,1,2,3),(default,2,3,4),(default,3,4,5)
      
      1. openSession()必须指定
        1. 底层 JDBCPreparedStatement.addBatch();
        factory.openSession(ExecutorType.BATCH);
        
    3. 示例
      1. collection=”xx” :要遍历的集合
      2. item: 迭代变量, #{迭代变量名}获取内容
        3.open: 循环后左侧添加的内容
      3. close: 循环后右侧添加的内容
      4. separator: 每次循环时,元素之间的分隔符
      <select id="selIn" parameterType="list" resultType="log">
          select * from log where id in
          <foreach collection="list" item="abc" open="(" close=")" separator=",">
              #{abc}
          </foreach>
      </select>
      
  10. <sql><include>
    1. 某些 SQL 片段如果希望复用,可以使用<sql>定义这个片段
    <sql id="mysql">
        id,accin,accout,money
    </sql>
    
  11. <select><delete><update><insert>中使用<include>引用
<select id="abc">
     select <include refid="mysql"></include>
     from log
 </select>

ThreadLocal

  1. 线程容器,给线程绑定一个 Object 内容,后只要线程不变,可以随时
    取出.
    1. 改变线程,无法取出内容.
  2. 语法示例
final ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("测试");
new Thread(){
    public void run() {
        String result = threadLocal.get();
        System.out.println("结果:"+result);
    };
}.start();

缓存

  1. 应用程序和数据库交互的过程是一个相对比较耗时的过程
  2. 缓存存在的意义:让应用程序减少对数据库的访问,提升程序运行
    效率
  3. MyBatis 中默认 SqlSession 缓存开启
    1. 同一个 SqlSession 对象调用同一个<select>时,只有第一次访问
      数据库,第一次之后把查询结果缓存到 SqlSession 缓存区(内存)中
    2. 缓存的是 statement 对象.(简单记忆必须是用一个<select>)
      1. myabtis 时一个<select>对应一个statement 对象
    3. 有效范围必须是同一个 SqlSession 对象
  4. 缓存流程
    1. 步骤一: 先去缓存区中找是否存在 statement
    2. 步骤二:返回结果
    3. 步骤三:如果没有缓存 statement 对象,去数据库获取数据
    4. 步骤四:数据库返回查询结果
    5. 步骤五:把查询结果放到对应的缓存区中
  5. SqlSessionFactory 缓存
    1. 又叫:二级缓存
    2. 有效范围:同一个 factory 内哪个SqlSession都可以获取
    3. 什么时候使用二级缓存:
      1. 当数据频繁被使用,很少被修改
    4. 使用二级缓存步骤
      1. mapper.xml 中添加
      <cache readOnly="true"></cache>
      
      1. 如果不写 readOnly=”true”需要把实体类序列化
  6. SqlSession 对象 close()时或 commit()时会把 SqlSession 缓存的数据刷(flush)到 SqlSessionFactory 缓存区中

Mybatis实现多表查询

  1. Mybatis 实现多表查询方式
    1. 业务装配.对两个表编写单表查询语句,在业务(Service)把查询
      的两个结果进行关联.
    2. 使用 Auto Mapping 特性,在实现两表联合查询时通过别名完成
      映射.
    3. 使用 MyBatis<resultMap>标签进行实现.
  2. 多表查询时,类中包含另一个类的对象的分类
    1. 单个对象
    2. 集合对象.

resultMap标签

  1. <resultMap>标签写在mapper.xml中,由程序员控制SQL查询结果与
    实体类的映射关系.

    1. 默认 MyBatis 使用 Auto Mapping 特性.
  2. 使用<resultMap>标签时,<select>标签不写 resultType 属性,而是使
    resultMap属性引用<resultMap>标签.

  3. 使用resultMap 实现单表映射关系

    1. 数据库设计
    idname
    1老师1
    2老师2
    1. 实体类设计
    public class Teacher{
        private int id1;
        private String name1;
        //get和set方法
        ...
    }
    
    1. mapper.xml 代码
    <resultMap type="teacher" id="mymap">
    <!-- 主键使用 id 标签配置映射关系 -->
        <id column="id" property="id1" />
    <!-- 其他列使用 result 标签配置映射关系 -->
        <result column="name" property="name1"/>
    </resultMap>
    <select id="selAll" resultMap="mymap">
        select * from teacher
    </select>
    
  4. 使用 resultMap 实现关联单个对象(N+1方式)

    1. N+1 查询方式,先查询出某个表的全部信息,根据这个表的信息
      查询另一个表的信息.
    2. 与业务装配的区别:
      1. service 里面写的代码,由 mybatis 完成装配
    3. 实现步骤:
      1. Student 实现类中包含了一个Teacher对象
      public class Student {
          private int id;
          private String name;
          private int age;
          private int tid;
          private Teacher teacher;
          //get 和 set 方法
          ...
      }
      
      1. TeacherMapper 中提供一个查询
      <select id="selById" resultType="teacher" parameterType="int">
          select * from teacher where id=#{0}
      </select>
      
      1. StudentMapper
        1. <association> 装配一个对象时使用
        2. property: 对象在类中的属性名
        3. select:通过哪个查询查询出这个对象的信息
        4. column: 把当前表的哪个列的值做为参数传递给另
          一个查询
        5. 大前提使用 N+1 方式.时如果列名和属性名相同可
          以不配置,使用 Auto mapping 特性.但是 mybatis 默认只会给列
          专配一次
        <resultMap type="student" id="stuMap">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="age" column="age"/>
            <result property="tid" column="tid"/>
            <!-- 如果关联一个对象 -->
            <association property="teacher" select="com.bjsxt.mapper.TeacherMapper.selById" column="tid"></association>
        </resultMap>
        <select id="selAll" resultMap="stuMap">
            select * from student
        </select>
        
        1. 把上面代码简化成
        <resultMap type="student" id="stuMap">
            <result column="tid" property="tid"/>
            <!-- 如果关联一个对象 -->
            <association property="teacher" select="com.bjsxt.mapper.TeacherMapper.selById" column="tid"></association>
        </resultMap>
        <select id="selAll" resultMap="stuMap">
            select * from student
        </select>
        
  5. 使用 resultMap 实现关联单个对象(联合查询方式)

    1. 只需要编写一个 SQL,在StudentMapper中添加下面效果
      1. <association/>只要专配一个对象就用这个标签
      2. 此时把<association/>当作小的<resultMap>看待
      3. javaType 属性:<association/>专配完后返回一个什么类型
        的对象.取值是一个类(或类的别名)
      <resultMap type="Student" id="stuMap1">
          <id column="sid" property="id"/>
          <result column="sname" property="name"/>
          <result column="age" property="age"/>
          <result column="tid" property="tid"/>
          <association property="teacher" javaType="Teacher" >
              <id column="tid" property="id"/>
              <result column="tname" property="name"/>
          </association>
      </resultMap>
      <select id="selAll1" resultMap="stuMap1">
          select s.id sid,s.name sname,age age,t.id
          tid,t.name tname FROM student s left outer join teacher
          t on s.tid=t.id
      </select>
      
  6. N+1 方式和联合查询方式对比

    1. N+1:需求不确定时.
    2. 联合查询:需求中确定查询时两个表一定都查询.
  7. N+1 名称由来

    1. 举例:学生中有 3 条数据
    2. 需求:查询所有学生信息级授课老师信息
    3. 需要执行的 SQL 命令
      1. 查询全部学生信息:select * from 学生
      2. 执行 3 遍 select * from 老师 where id=学生的外键
    4. 使用多条 SQl 命令查询两表数据时,如果希望把需要的数据都
      查询出来,需要执行N+1SQl才能把所有数据库查询出来.
    5. 缺点:
      1. 效率低
    6. 优点:
      1. 如果有的时候不需要查询学生是同时查询老师.只需要
        执行一个select * from student;
    7. 适用场景: 有的时候需要查询学生同时查询老师,有的时候只
      需要查询学生.
    8. 如何解决 N+1 查询带来的效率低的问题
      1. 默认带的前提: 每次都是两个都查询.
      2. 使用两表联合查询.

使用查询关联集合对象(N+1)

  1. Teacher中添加 List<Student>
public class Teacher {
    private int id;
    private String name;
    private List<Student> list;
    //get和set方法
    ...
  1. StudentMapper.xml 中添加通过 tid 查询
<select id="selByTid" parameterType="int" resultType="student">
    select * from student where tid=#{0}
</select>
  1. TeacherMapper.xml中添加查询全部
    1. <collection/>属性是集合类型时使用的标签.
    <resultMap type="teacher" id="mymap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <collection property="list" select="com.bjsxt.mapper.StudentMapper.selByTid" column="id"></collection>
    </resultMap>
    <select id="selAll" resultMap="mymap">
        select * from teacher
    </select>
    

使用实现加载集合数据(联合查询方式)

  1. teacherMapper.xml 中添加
    1. mybatis 可以通过主键判断对象是否被加载过.
    2. 不需要担心创建重复 Teacher
    <resultMap type="teacher" id="mymap1">
        <id column="tid" property="id"/>
        <result column="tname" property="name"/>
        <collection property="list" ofType="student" >
            <id column="sid" property="id"/>
            <result column="sname" property="name"/>
            <result column="age" property="age"/>
            <result column="tid" property="tid"/>
        </collection>
    </resultMap>
    <select id="selAll1" resultMap="mymap1">
        select t.id tid,t.name tname,s.id sid,s.name
        sname,age,tid from teacher t LEFT JOIN student s on
        t.id=s.tid;
    </select>
    

使用 Auto Mapping 结合别名实现多表查询.

  1. 只能使用多表联合查询方式.
  2. 要求:查询出的列别和属性名相同.
  3. 实现方式
    1. SQL是关键字符,两侧添加反单引号
    <select id="selAll" resultType="student">
        select t.id `teacher.id`,t.name
        `teacher.name`,s.id id,s.name name,age,tid
        from student s LEFT JOIN teacher t on t.id=s.tid
    </select>
    

Mybatis注解

  1. 注解:为了简化配置文件.
    2.Mybatis的注解简化 mapper.xml 文件.
    1. 如果涉及动态 SQL 依然使用 mapper.xml
  2. mapper.xml和注解可以共存.
  3. 使用注解时 mybatis.xml<mappers>使用
    1. <package/>
    2. <mapper class=””/>
  4. 实现查询
@Select("select * from teacher")
List<Teacher> selAll();
  1. 实现新增
@Insert("insert into teacher
values(default,#{name})")
int insTeacher(Teacher teacher);
  1. 实现修改
@Update("update teacher set name=#{name} where
id=#{id}")
int updTeacher(Teacher teacher);
  1. 实现删除
@Delete("delete from teacher where id=#{0}")
int delById(int id);
  1. 使用注解实现<resultMap>功能(一般不用注解实现)
    1. N+1 举例
    2. StudentMapper 接口添加查询
    @Select("select * from student where tid=#{0}")
    List<Student> selByTid(int tid);
    
    1. TeacherMapper 接口添加
      1. @Results() 相当于<resultMap>
      2. @Result() 相当于<id/><result/>
        1. @Result(id=true) 相当与<id/>
      3. @Many() 相当于<collection/>
      4. @One() 相当于<association/>
      @Results(value={ @Result(id=true,property="id",column="id"),
      @Result(property="name",column="name"),
      @Result(property="list",column="id",many=@Many(select="com.bjsxt.mapper.StudentMapper.selByTid"))})
      @Select("select * from teacher")
      List<Teacher> selTeacher();
      

Mybatis运行原理

  1. 运行过程中涉及到的类
    1. Resources: MyBatisIO 流的工具类,加载配置文件
    2. SqlSessionFactoryBuilder(): 构建器
      1. 作用:创建 SqlSessionFactory 接口的实现类
    3. XMLConfigBuilder: MyBatis 全局配置文件内容构建器类
      1. 作用: 负责读取流内容并转换为 JAVA 代码.
    4. Configuration 封装了全局配置文件所有配置信息.
      1. 全局配置文件内容存放在Configuration
    5. DefaultSqlSessionFactorySqlSessionFactory接口的实现类
    6. Transaction 事务类
      1. 每一个 SqlSession 会带有一个 Transaction 对象.
    7. TransactionFactory 事务工厂
      1. 作用: 负责生产 Transaction
    8. Executor: MyBatis 执行器
      1. 作用:负责执行 SQL 命令
      2. 相当于 JDBCstatement 对象(或 PreparedStatement
        CallableStatement)
      3. 默认的执行器 SimpleExcutor
      4. 批量操作 BatchExcutor
      5. 通过 openSession(参数控制)
    9. DefaultSqlSessionSqlSession 接口的实现类
    10. ExceptionFactory: MyBatis 中异常工厂
  2. 流程图
graph TD
A[Resources加载全局配置文件];
B[实例化SqlSessionFactoryBuilder构建器];
C[由XMLConfigBuilder解析配置文件流];
D[把配置信息放在Configuration中];
E[实例化SqlSessionFactory实现类DefaultSqlSessionFactory];
F[由TransactionFactory创建一个Transaction事物对象];
G[创建执行器Excutor];
H[创建SqlSession接口实现类DefaultSqlSession];
I[实现CURD];
J{执行是否成功};
K[事务提交];
L[关闭];
A-->B
B-->C
C-->D
D-->E
E-->F
F-->G
G-->H
H-->I
I-->F
I-->J
J--成功-->K
J--失败,事物回滚-->F
K-->L
  1. 文字解释
    MyBatis 运行开始时需要先通过Resources加载全局配置文件.下面
    需要实例化 SqlSessionFactoryBuilder构建器.帮助SqlSessionFactory 接口实现类 DefaultSqlSessionFactory. 在实例化 DefaultSqlSessionFactory 之前需要先创建 XmlConfigBuilder
    解析全局配置文件流,并把解析结果存放在 Configuration 中.之后把
    Configuratin 传递给DefaultSqlSessionFactory.到此SqlSessionFactory
    厂创建成功. 由SqlSessionFactory工厂创建SqlSession. 每次创建 SqlSession时,都需要由 TransactionFactory创建 Transaction
    对象,同时还需要创建 SqlSession的执行器Excutor,最后实例化
    DefaultSqlSession,传递给 SqlSession 接口. 根据项目需求使用 SqlSession 接口中的 API 完成具体的事务操作. 如果事务执行失败,需要进行 rollback 回滚事务. 如果事务执行成功提交给数据库.关闭 SqlSession
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值