[记录学习]自学动力节点老杜MyBatis笔记_01

MyBatis自学笔记

学习来源:B站
https://www.bilibili.com/video/BV1JP4y1Z73S?p=1&vd_source=07c8a1a7d89af39fe20c3a6894f5ff6a
资料来源:百度网盘
链接:https://pan.baidu.com/s/1tIx_hLeENVBP4a4F83C5gg?pwd=3k1d
提取码:3k1d

环境

在这里插入图片描述

一、MyBatis概述

1.1 框架

  • 在⽂献中看到的framework被翻译为框架
  • 框架其实就是对通⽤代码的封装,提前写好了⼀堆接⼝和类,我们可以在做项⽬的时候直接引⼊这些 接⼝和类(引⼊框架),基于这些现有的接⼝和类进⾏开发,可以⼤⼤提⾼开发效率。
  • 框架⼀般都以jar包的形式存在。(jar包中有class⽂件以及各种配置⽂件等。)
  • SSM三⼤框架的学习顺序:
    • ⽅式⼀:MyBatis、Spring、SpringMVC(建议)
    • ⽅式⼆:Spring、MyBatis、SpringMVC

1.2 三层架构

在这里插入图片描述

  • 表现层(UI):直接跟前端打交互(⼀是接收前端ajax请求,⼆是返回json数据给前端)
  • 业务逻辑层(BLL):⼀是处理表现层转发过来的前端请求(也就是具体业务),⼆是将从持久层获取的数据返回到表现层。
  • 数据访问层(DAL):直接操作数据库完成CRUD,并将获得的数据返回到上⼀层(也就是业务逻辑层)。
  • Java持久层框架:(常用)
    • MyBatis
    • Spring Data(实现了JPA规范)

1.3 JDBC不足

  • SQL语句写死在Java程序中,不灵活。改SQL的话就要改Java代码。违背开闭原则OCP。
  • 给?传值是繁琐的。能不能⾃动化???
  • 将结果集封装成Java对象是繁琐的。能不能⾃动化???

1.4 了解MyBatis

  • MyBatis本质上就是对JDBC的封装,通过MyBatis完成CRUD。

  • MyBatis在三层架构中负责持久层的,属于持久层框架。

  • ORM:对象关系映射

    • O(Object):Java虚拟机中的Java对象

    • R(Relational):关系型数据库

    • M(Mapping):将Java虚拟机中的Java对象映射到数据库表中⼀⾏记录,或是将数据库表中 ⼀⾏记录映射成Java虚拟机中的⼀个Java对象。

    • 图示:

      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    • MyBatis属于半⾃动化ORM框架。

    • Hibernate属于全⾃动化的ORM框架。

  • MyBatis框架特点:

    • ⽀持定制化 SQL、存储过程、基本映射以及⾼级映射
    • 避免了⼏乎所有的 JDBC 代码中⼿动设置参数以及获取结果集
    • ⽀持XML开发,也⽀持注解式开发。【为了保证sql语句的灵活,所以mybatis⼤部分是采⽤ XML⽅式开发。】
    • 将接⼝和 Java 的 POJOs(Plain Ordinary Java Object,简单普通的Java对象)映射成数据库中的记录
    • 体积⼩好学:两个jar包,两个XML配置⽂件。
    • 完全做到sql解耦合。
    • 提供了基本映射标签。
    • 提供了⾼级映射标签。
    • 提供了XML标签,⽀持动态SQL的编写。

二、MyBatis入门程序

只要你会JDBC,MyBatis就可以学。

2.1 版本

软件:

  • IntelliJ IDEA:2022.1.4
  • Navicat for MySQL:16.0.14
  • MySQL数据库:8.0.30

组件:

  • MySQL驱动:8.0.30
  • MyBatis:3.5.10
  • JDK:Java17
  • JUnit:4.13.2
  • Logback:1.2.11

2.2 MyBatis下载

  • 从github上下载,地址:https://github.com/mybatis/mybatis-3

在这里插入图片描述

在这里插入图片描述

  • 将框架以及框架的源码都下载下来,下载框架后解压,打开mybatis⽬录

在这里插入图片描述

  • 通过以上解压可以看到,框架⼀般都是以jar包的形式存在。我们的mybatis课程使⽤maven,所以这个jar我们不需要。
  • 官⽅⼿册需要。

2.3 MyBatis入门程序开发步骤

  • 数据库准备,使用Navicat for MySQL建表t_car插入数据

在这里插入图片描述

在这里插入图片描述

  • 创建Project:建议创建Empty Project,设置Java版本以及编译版本等。

在这里插入图片描述

在这里插入图片描述

  • 设置IDEA的maven

在这里插入图片描述

  • 创建Module:普通的Maven Java模块

在这里插入图片描述

  • 步骤1:打包⽅式:jar(不需要war,因为mybatis封装的是jdbc。)

    <groupId>com.shanglinsong</groupId>
    <artifactId>mybatis-001-introduction</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--打包方式jar-->
    <packaging>jar</packaging>
    
  • 步骤2:引⼊依赖(mybatis依赖 + mysql驱动依赖)

    <!-- mybatis依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.10</version>
    </dependency>
    
    <!-- mysql依赖 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    
  • 步骤3:在resources根⽬录下新建mybatis-config.xml配置⽂件(可以参考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>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                    <property name="username" value="root"/>
                    <property name="password" value="******"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <!--执行XxxMapper.xml文件的路径-->
            <!--resource属性自动会从类的根路径下开始查找资源。-->
            <mapper resource="CarMapper.xml"/>
        </mappers>
    </configuration>
    
    • 注意1:mybatis核⼼配置⽂件的⽂件名不⼀定是mybatis-config.xml,可以是其它名字。
    • 注意2:mybatis核⼼配置⽂件存放的位置也可以随意。这⾥选择放在resources根下,相当于放到了类的根路径下。
  • 步骤4:在resources根⽬录下新建CarMapper.xml配置⽂件(可以参考mybatis⼿册拷⻉)

    <?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">
    
    <mapper namespace="sls">
    
        <!--insert语句,id是这条sql语句的唯一标识,这个id就代表了这条SQL语句。-->
        <insert id="insertCar">
            insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
            values(null,'1003','丰田霸道',30.0,'2000-10-11','燃油车')
        </insert>
    
    </mapper>
    
    • 注意1:sql语句最后结尾可以不写“;”

    • 注意2:CarMapper.xml⽂件的名字不是固定的。可以使⽤其它名字。

    • 注意3:CarMapper.xml⽂件的位置也是随意的。这⾥选择放在resources根下,相当于放到了类的根路 径下。

    • 注意4:将CarMapper.xml⽂件路径配置到mybatis-config.xml:

      <mappers>
          <!--执行XxxMapper.xml文件的路径-->
          <!--resource属性自动会从类的根路径下开始查找资源。-->
          <mapper resource="CarMapper.xml"/>
      </mappers>
      
  • 步骤5:编写MyBatisIntroductionTest代码

    package com.powernode.mybatis.test;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class MyBatisIntroductionTest {
        public static void main(String[] args) throws IOException {
    
            // 获取SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    
            // 获取SqlSessionFactory对象
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); 
            // Resources.getResourceAsStream默认就是从类的根路径下开始查找资源。
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); 
            // 一般情况下都是一个数据库对应一个SqlSessionFactory对象。
    
            // 获取SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            // 执行Sql语句
            int count = sqlSession.insert("insertCar");
            System.out.println("插入了 " + count + " 条记录");
    
            // 手动提交
            sqlSession.commit();
        }
    }
    
    • 注意1:默认采⽤的事务管理器是:JDBC。JDBC事务默认是不提交的,需要⼿动提交。
  • 步骤6:运⾏程序,查看运⾏结果,以及数据库表中的数据

在这里插入图片描述

在这里插入图片描述

2.4 关于MyBatis核心配置文件的名字和路径详解

  • 经过测试说明mybatis核⼼配置⽂件的名字是随意的,存放路径也是随意的。
  • 虽然mybatis核⼼配置⽂件的名字不是固定的,但通常该⽂件的名字叫做:mybatis-config.xml
  • 虽然mybatis核⼼配置⽂件的路径不是固定的,但通常该⽂件会存放到类路径当中,这样让项⽬的移植更 加健壮。
  • 在mybatis中提供了⼀个类:Resources【org.apache.ibatis.io.Resources】,该类可以从类路径当 中获取资源,我们通常使⽤它来获取输⼊流InputStream,代码如下:
// 这种方式只能从类路径当中获取资源,也就是说mybatis-config.xml文件需要在类路径下
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

2.5 MyBatis第一个比较完整的代码写法

package com.powernode.mybatis.test;

/**
* 采用正规的方式,写一个完整的MyBatis程序
* @author BenShang
* @version 1.0
* @since 1.0
* */

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;

public class MyBatisCompleteTest {
    public static void main(String[] args) {
        SqlSession sqlSession = null;
        try {
            // 1. 创建SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 2. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
            // 3. 创建SqlSession对象,开启会话(底层会开启事务)
            sqlSession = sqlSessionFactory.openSession();
            // 4. 执行sql语句,处理相关业务
            int count = sqlSession.insert("insertCar");
            System.out.println(count);
            // 5. 执行到这里,没有发生任何异常,提交事务,终止事务。
            sqlSession.commit();
        } catch (IOException e) {
            // 发生异常最好回滚事务
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            e.printStackTrace();
        }finally {
            // 6. 关闭会话(释放资源)
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}

2.6 引入JUnit

  • JUnit是专⻔做单元测试的组件。

    • 在实际开发中,单元测试⼀般是由我们Java程序员来完成的。
    • 我们要对我们⾃⼰写的每⼀个业务⽅法负责任,要保证每个业务⽅法在进⾏测试的时候都能通 过。
    • 测试的过程中涉及到两个概念:
      • 期望值
      • 实际值
    • 期望值和实际值相同表示测试通过,期望值和实际值不同则单元测试执⾏时会报错。
  • 这⾥引⼊JUnit是为了代替main⽅法。

  • 使⽤JUnit步骤:

    • 第⼀步:引⼊依赖
    <!-- junit依赖 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    
    • 第⼆步:编写单元测试类【测试⽤例】,测试⽤例中每⼀个测试⽅法上使⽤@Test注解进⾏标注。

      • 测试⽤例的名字以及每个测试⽅法的定义都是有规范的:

        • 测试⽤例的名字:XxxTest
        • 测试⽅法声明格式:public void test业务⽅法名(){}
        // 测试用例
        public class CarMapperTest{
        	// 测试方法
            @Test
            public void testInsert(){}
            
            @Test
            public void testUpdate(){}
        }
        
    • 第三步:可以在类上执⾏,也可以在⽅法上执⾏

      • 在类上执⾏时,该类中所有的测试⽅法都会执⾏。
      • 在⽅法上执⾏时,只执⾏当前的测试⽅法。
  • 编写⼀个测试⽤例,来测试insertCar业务

    package com.powernode.mybatis.test;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    
    import java.io.IOException;
    
    public class CarMapperTest {
    
        @Test
        public void testInsertCar(){
            SqlSession sqlSession = null;
            try {
                // 1. 创建SqlSessionFactoryBuilder对象
                SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
                // 2. 创建SqlSessionFactory对象
                SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
                // 3. 创建SqlSession对象,开启会话(底层会开启事务)
                sqlSession = sqlSessionFactory.openSession();
                // 4. 执行sql语句,处理相关业务
                int count = sqlSession.insert("insertCar");
                System.out.println(count);
                // 5. 执行到这里,没有发生任何异常,提交事务,终止事务。
                sqlSession.commit();
            } catch (IOException e) {
                // 发生异常最好回滚事务
                if (sqlSession != null) {
                    sqlSession.rollback();
                }
                e.printStackTrace();
            }finally {
                // 6. 关闭会话(释放资源)
                if (sqlSession != null) {
                    sqlSession.close();
                }
            }
        }
    }
    

2.7 引入日志框架logback

  • 引⼊⽇志框架的⽬的是为了看清楚mybatis执⾏的具体sql。
  • 启⽤标准⽇志组件,只需要在mybatis-config.xml⽂件中添加以下配置:【可参考mybatis⼿册】
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

标准⽇志也可以⽤,但是配置不够灵活,可以集成其他的⽇志组件,例如:log4j,logback等。

  • logback是⽬前⽇志框架中性能较好的,较流⾏的,所以我们选它。

  • 引⼊logback的步骤:

    • 第⼀步:引⼊logback相关依赖
    <!-- 引入logback的依赖,这个日志框架实现了slf4j规范 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.11</version>
    </dependency>
    
    • 第⼆步:引⼊logback相关配置⽂件(⽂件名叫做logback.xml或logback-test.xml,放到类路径当中)
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!--定义日志文件的存储地址-->
    <property name="LOG_HOME" value="/home"/>
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5
           个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5
           个字符宽度%msg:日志消息,%n是换⾏符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logge
                r{50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>100MB</MaxFileSize>
        </triggeringPolicy>
    </appender>
    <!--mybatis log configure-->
    <logger name="com.apache.ibatis" level="TRACE"/>
    <logger name="java.sql.Connection" level="DEBUG"/>
    <logger name="java.sql.Statement" level="DEBUG"/>
    <logger name="java.sql.PreparedStatement" level="DEBUG"/>
    <!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>
  • 再次执⾏单元测试⽅法testInsertCar,查看控制台是否有sql语句输出

在这里插入图片描述

2.8 MyBatis工具类SqlSessionUtil的封装

  • 每⼀次获取SqlSession对象代码太繁琐,封装⼀个⼯具类

    package com.powernode.mybatis.utils;
    
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    
    /**
     * MyBatis工具类
     * @author Shanglinsong
     * @version 1.0
     * @sine 1.0
     */
    
    public class SqlSessionUtil {
    
        // 工具类的构造方法一般都是私有化的。
        // 工具类中所有的方法都是静态的,直接采用类名调用即可,不需要new对象。
        // 为了防止new对象,构造方法私有化
        private SqlSessionUtil() {
        }
    
        private static SqlSessionFactory sqlSessionFactory;
    
        // 类加载时执行
        // SqlSessionUtil工具类在进行第一次加载的时候,解析mybatis-config.xml文件,创建SqlSessionFactory对象。
        static{
            try {
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        /*public static SqlSession openSession(){
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // SqlSessionFactory对象:一个SqlSessionFactory对应一个environment,一个environment通常是一个数据库。
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
            SqlSession sqlSession = sqlSessionFactory.openSession();
            return sqlSession;
        }*/
    
        /**
         * 获取SqlSession对象
         * @return SqlSession
         */
        public static SqlSession openSession(){
            return sqlSessionFactory.openSession();
        }
    }
    
  • 测试⼯具类,将testInsertCar()改造

    @Test
    public void testSqlSessionUtil(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        // 执行sql语句
        int count = sqlSession.insert("insertCar");
        System.out.println("插入了" + count + "条记录");
        // 提交
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
    

第一个MyBatis程序的Readme.txt笔记

开发我的第一个MyBatis程序

1. resources目录:
    放在这个目录当中的,一般都是资源文件,配置文件。
    直接放到resources目录下的资源,等同于放到了类
    的根路径下。

2. 开发步骤
* 第一步:打包方式jar
* 第二步:引入依赖
    - mybatis依赖
    - mysql驱动依赖
* 第三步:编写mybatis核心配置文件:mybatis-config.xml
    注意:
        第一:这个文件名不是必须叫做mybatis-config.xml,可以用其他的名字。只是大家都采用这个名字。
        第二:这个文件存放的位置也不是固定的,可以随意,但一般情况下,会放到类的根路径下。

    mybatis-config.xml文件中的配置信息不理解没关系,先把连接数据库的信息修改以下即可。
    其他的别动。
* 第四步:编写XxxxMapper.xml文件
    在这个配置文件当中编写SQL语句。
    这个文件名也不是固定的,放的位置也不是固定,我们这里给它起个名字,叫做:CarMapper.xml
    把它暂时放到类的根路径下。
* 第五步:在mybatis-config.xml文件中指定XxxxMapper.xml文件的路径:
    <mapper resource="CarMapper.xml"/>
    注意:resource属性会自动从类的根路径下开始查找资源。

* 第六步:编写MyBatis程序。(使用mybatis的类库,编写mybatis程序,连接数据库,做增删改查就行了。)
    在MyBatis当中,负责执行SQL语句的那个对象叫做什么呢?
        SqlSession
    SqlSession是专门用来执行SQL语句的,是一个Java程序和数据库之间的一次会话。
    要想获取SqlSession对象,需要先获取SqlSessionFactory对象,通过SqlSessionFactory工厂来生产SqlSession对象。
    怎么获取SqlSessionFactory对象呢?
        需要首先获取SqlSessionFactoryBuilder对象。
        通过SqlSessionFactoryBuilder对象的build方法,来获取一个SqlSessionFactory对象。

    mybatis的核心对象包括:
        SqlSessionFactoryBuilder
        SqlSessionFactory
        SqlSession

    SqlSessionFactoryBuilder --> SqlSessionFactory --> SqlSession


3. 从 XML 中构建 SqlSessionFactory
    通过官方的这句话,你能想到什么呢?
        第一:在MyBatis中一定是有一个很重要的对象,这个对象是:SqlSessionFactory对象。
        第二:SqlSessionFactory对象的创建需要XML。
    XML是什么?
        它一定是一个配置文件。

4. mybatis中有两个主要的配置文件:
    其中一个是:mybatis-config.xml,这是核心配置文件,主要配置连接数据库的信息等。(一个)
    另一个是:XxxxMapper.xml,这个文件是专门用来编写SQL语句的配置文件。(一个表一个)
        t_user表,一般会对应一个UserMapper.xml
        t_student表,一般会对应一个StudentMapper.xml

5. 关于第一个程序的小细节
    * mybatis中sql语句的结尾";"可以省略。
    * Resources.getResourceAsStream
        小技巧:以后凡是遇到resource这个单词,大部分情况下,这种加载资源的方式就是从类的根路径下开始加载。(开始查找)
        优点:采用这种方式,从类路径当中加载资源,项目的移植性很强。项目从windows移植到linux,代码不需要修改,因为这个资源文件一直都在类路径当中。
    * InputStream is = new FileInputStream("d:\\mybatis-config.xml");
        采用这种方式也可以。
        缺点:可移植性太差,程序不够健壮。可能会移植到其他的操作系统当中。导致以上路径无效,还需要修改java代码中的路径。这样违背了OCP原则。
    * 已经验证了:
        mybatis核心配置文件的名字,不一定是:mybatis-config.xml。可以是其它名字。
        mybatis核心配置文件存放的路径,也不一定是在类的根路径下。可以放到其它位置。但为了项目的移植性,健壮性,最好将这个配置文件放到类路径下面。
    * InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
        ClassLoader.getSystemClassLoader() 获取系统的类加载器。
        系统类加载器有一个方法叫做:getResourceAsStream
        它就是从类路径当中加载资源的。
        通过源代码分析发现:
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            底层的源代码其实就是:
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
    * CarMapper.xml文件的名字是固定的吗?CarMapper.xml文件的路径是固定的吗?
        都不是固定的。
        <mapper resource="CarMapper.xml"/> resource属性:这种方式是从类路径当中加载资源。
        <mapper url="file:///d:/CarMapper.xml"/> url属性:这种方式是从绝对路径当中加载资源。

6. 关于mybatis的事务管理机制。(深度剖析)

    * 在mybatis-config.xml文件中,可以通过以下的配置进行mybatis的事务管理
        <transactionManager type="JDBC"/>
    * type属性的值包括两个:
        JDBC(jdbc)
        MANAGED(managed)
        type后面的值,只有以上两个值可选,不区分大小写。
    * 在mybatis中提供了两种事务管理机制:
        第一种:JDBC事务管理器
        第二种:MANAGED事务管理器
    * JDBC事务管理器:
        mybatis框架自己管理事务,自己采用原生的JDBC代码去管理事务:
            conn.setAutoCommit(false); 开启事务。
            ....业务处理...
            conn.commit(); 手动提交事务
        使用JDBC事务管理器的话,底层创建的事务管理器对象:JdbcTransaction对象。

        如果你编写的代码是下面的代码:
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
            表示没有开启事务。因为这种方式压根不会执行:conn.setAutoCommit(false);
            在JDBC事务中,没有执行conn.setAutoCommit(false);那么autoCommit就是true。
            如果autoCommit是true,就表示没有开启事务。只要执行任意一条DML语句就提交一次。

    * MANAGED事务管理器:
        mybatis不再负责事务的管理了。事务管理交给其它容器来负责。例如:spring。
        我不管事务了,你来负责吧。

        对于我们当前的单纯的只有mybatis的情况下,如果配置为:MANAGED
        那么事务这块是没人管的。没有人管理事务表示事务压根没有开启。

        没有人管理事务就是没有事务。

    * JDBC中的事务:
        如果你没有在JDBC代码中执行:conn.setAutoCommit(false);的话,默认的autoCommit是true。

    * 重点:
        以后注意了,只要你的autoCommit是true,就表示没有开启事务。
        只有你的autoCommit是false的时候,就表示开启了事务。

7. 关于mybatis集成日志组件。让我们调试起来更加方便。

    * mybatis常见的集成的日志组件有哪些呢?
        SLF4J(沙拉风):沙拉风是一个日志标准,其中有一个框架叫做logback,它实现了沙拉风规范。
        LOG4J
        LOG4J2
        STDOUT_LOGGING
        ....

        注意:log4j log4j2 logback都是同一个作者开发的。

    * 其中STDOUT_LOGGING是标准日志,mybatis已经实现了这种标准日志。mybatis框架本身已经实现了这种标准。
    只要开启即可。怎么开启呢?在mybatis-config.xml文件中使用settings标签进行配置开启。
        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
        这个标签在编写的时候要注意,它应该出现在environments标签之前。注意顺序。当然,不需要记忆这个顺序。
        因为有dtd文件进行约束呢。我们只要参考dtd约束即可。

        这种实现也是可以的,可以看到一些信息,比如:连接对象什么时候创建,什么时候关闭,sql语句是怎样的。
        但是没有详细的日期,线程名字,等。如果你想使用更加丰富的配置,可以集成第三方的log组件。

    * 集成logback日志框架。
        logback日志框架实现了slf4j标准。(沙拉风:日志门面。日志标准。)
        第一步:引入logback的依赖。
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.11</version>
            </dependency>
        第二步:引入logback所必须的xml配置文件。
            这个配置文件的名字必须叫做:logback.xml或者logback-test.xml,不能是其它的名字。
            这个配置文件必须放到类的根路径下。不能是其他位置。
            主要配置日志输出相关的级别以及日志具体的格式。

三、使用MyBatis完成CRUD

  • 准备⼯作
    • 创建module(Maven的普通Java模块):mybatis-002-crud
    • pom.xml
      • 打包⽅式jar
      • 依赖:
        • mybatis依赖
        • mysql驱动依赖
        • junit依赖
        • logback依赖
    • mybatis-config.xml放在类的根路径下
    • CarMapper.xml放在类的根路径下
    • logback.xml放在类的根路径下
    • 提供com.powernode.mybatis.utils.SqlSessionUtil⼯具类
    • 创建测试⽤例:com.powernode.mybatis.CarMapperTest

3.1 insert(Create, 增)

  • SQL语句中的值不应该写死,值应该是⽤户提供的。

  • 在MyBatis中可以这样做:

    • 在Java程序中,将数据放到Map集合中
    • 在sql语句中使⽤ #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符
  • 利用Map集合进行insert

    • java程序
    @Test
    public void testInsertCarByMap(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        // 前端传过来数据了。
        // 这个对象我们先使用Map集合进行数据的封装。
        HashMap<String, Object> map = new HashMap<>();
    
        map.put("carNum", "1111");
        map.put("brand", "比亚迪汉2");
        map.put("guidePrice", 10.0);
        map.put("produceTime", "2010-11-11");
        map.put("carType", "电车");
    
        // 执行SQL语句
        // insert方法的参数:
        // 第一个参数:sqlId,从CarMapper.xml文件中复制。
        // 第二个参数:封装数据的对象。
        int count = sqlSession.insert("insertCar", map);
        System.out.println("插入了几条数据:" + count);
    
        sqlSession.commit();
        sqlSession.close();
    }
    
    • mapper文档:
    <insert id="insertCar">
        insert into t_car(car_num,brand,guide_price,produce_time,car_type)
        values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    </insert>
    
    • 注意:
      • #{} 的⾥⾯必须填写map集合的key,不能随便写。
      • 如果采⽤map集合传参,#{} 里写的是map集合的key,如果key不存在不会报错,数据库表中会插入NULL。
  • 使⽤pojo(简单普通的java对象)完成进行insert

    • 第⼀步:定义⼀个pojo类Car,提供相关属性。
    package com.powernode.mybatis.pojo;
    
    /**
     * 封装汽车的相关信息的pojo类,普通的java类
     * @author ShiningSong
     * @version 1.0
     * @since 1.0
     */
    
    public class Car {
        // 数据库表中的字段应该和pojo类的属性一一对应。
        // 建议使用包装类,这样可以防止null的问题。
        private Long id;
        private String carNum;
        private String brand;
        private Double guidePrice;
        private String produceTime;
        private String carType;
    
        public Car() {
        }
    
        public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
            this.id = id;
            this.carNum = carNum;
            this.brand = brand;
            this.guidePrice = guidePrice;
            this.produceTime = produceTime;
            this.carType = carType;
        }
    
        @Override
        public String toString() {
            return "Car{" +
                    "id=" + id +
                    ", carNum='" + carNum + '\'' +
                    ", brand='" + brand + '\'' +
                    ", guidePrice=" + guidePrice +
                    ", produceTime='" + produceTime + '\'' +
                    ", carType='" + carType + '\'' +
                    '}';
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getCarNum() {
            return carNum;
        }
    
        public void setCarNum(String carNum) {
            this.carNum = carNum;
        }
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public Double getGuidePrice() {
            return guidePrice;
        }
    
        public void setGuidePrice(Double guidePrice) {
            this.guidePrice = guidePrice;
        }
    
        public String getProduceTime() {
            return produceTime;
        }
    
        public void setProduceTime(String produceTime) {
            this.produceTime = produceTime;
        }
    
        public String getCarType() {
            return carType;
        }
    
        public void setCarType(String carType) {
            this.carType = carType;
        }
    }
    
    • 第二步:java程序
    @Test
    public void testInsertCarByPOJO(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        // 封装数据
        Car car = new Car(null, "3333", "比亚提秦", 30.0, "2020-11-11", "新能源");
        // 执行sql
        int count = sqlSession.insert("insertCar", car);
        System.out.println("插入了几条数据:" + count);
    
        sqlSession.commit();
        sqlSession.close();
    }
    
    • 第三步:sql语句
    <insert id="insertCar">
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
        values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    </insert>
    
    • 注意

      • 如果采⽤POJO传参,#{} ⾥写的是get⽅法的⽅法名去掉get之后将剩下的单词⾸字⺟变⼩写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get⽅法不存在会报错。
      • 注意:其实传参数的时候有⼀个属性parameterType,这个属性⽤来指定传参的数据类型,不过这个属性是可以省略的
      <!-- pojo类 -->
      <insert id="insertCarByPOJO" parameterType="com.powernode.mybatis.pojo.Car">
          insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
          values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
      </insert>
      <!-- Map -->
      <insert id="insertCar" parameterType="java.util.Map">
          insert into t_car(car_num,brand,guide_price,produce_time,car_type)
          values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
      </insert>
      

3.2 delete(Delete, 删)

  • 需求:根据id进⾏删除。
  • mapper文件:
<delete id="deleteById">
    delete from t_car where id=#{carNum}
</delete>
  • java程序:
@Test
public void testDeleteById(){
    SqlSession sqlSession = SqlSessionUtil.openSession();
    // 执行sql语句
    int count = sqlSession.delete("deleteById", 16);
    System.out.println("删除了几条记录:" + count);
    sqlSession.commit();
    sqlSession.close();
}
  • 注意:当占位符只有⼀个的时候,#{} ⾥⾯的内容可以随便写。

3.3 update(Update, 改)

  • 需求:修改id=9的Car信息,car_num为102,brand为⽐亚迪汉,guide_price为30.23,produce_time 为2018-09-10,car_type为电⻋
  • mapper文件:
<update id="updateById">
    update t_car
    set car_num=#{carNum}, brand=#{brand}, guide_price=#{guidePrice},
    	produce_time=#{produceTime}, car_type=#{carType}
    where id=#{id}
</update>
  • java程序:
@Test
public void testUpdateById(){
    SqlSession sqlSession = SqlSessionUtil.openSession();
    // 更新车辆信息
    Car car = new Car(9L, "102", "比亚迪汉", 30.23, "2018-09-10", "电车");
    // 执行sql语句
    int count = sqlSession.update("updateById", car);
    System.out.println("更新了几条数据:" + count);

    sqlSession.commit();
    sqlSession.close();
}
  • 使⽤map传数据也是可以的。

3.4 select(Retrieve, 查)

select语句和其它语句不同的是:查询会有⼀个结果集。

  • 单条查询

    • 需求:查询id为1的Car信息
    • mapper文件:
    <select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
        select id, car_num as carNum, brand, guide_price as guidePrice,
        		produce_time as produceTime, car_type as carType
        from t_car where id=#{id}
    </select>
    
    • java程序:

      @Test
      public void testSelectById(){
          SqlSession sqlSession = SqlSessionUtil.openSession();
          // 执行sql语句
          Object car = sqlSession.selectOne("selectById", 1);
          // 输出结果
          System.out.println(car);
          sqlSession.commit();
          sqlSession.close();
      }
      
    • 注意:

      • <select>标签中添加resultType属性,⽤来指定查询要转换的类型,不能省略,否则会报错
      • 通过测试得知,如果当查询结果的字段名和java类的属性名对应不上的话,可以采⽤as关键字起别名,否则该属性查询结果会为null值
  • 多条查询

    • 需求:查询所有的Car信息。
    • mapper文件:
    <select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
        select id, car_num as carNum, brand, guide_price as guidePrice,
        produce_time as produceTime, car_type as carType
        from t_car
    </select>
    
    • java程序:
    @Test
    public void testSelectAll(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        // 执行sql语句
        List<Object> cars = sqlSession.selectList("selectAll");
        // 输出结果
        cars.forEach(car -> System.out.println(car));
        sqlSession.commit();
        sqlSession.close();
    }
    

3.5 关于SQL Mapper的namespace

  • 在SQL Mapper配置⽂件中标签的namespace属性可以翻译为命名空间,这个命名空间主要是 为了防⽌SQL语句的ID冲突的。

  • 创建UserMapper.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">

<mapper namespace="car2">
    <select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
        select id, car_num as carNum, brand, guide_price as guidePrice,
               produce_time as produceTime, car_type as carType
        from t_car
    </select>
</mapper>
  • 不难看出,CarMapper.xml和UserMapper.xml⽂件中都有 id=“selectCarAll”
  • 将CarMapper2.xml配置到mybatis-config.xml⽂件中。
<mappers>
    <mapper resource="CarMapper.xml"/>
    <mapper resource="UserMapper.xml"/>
</mappers>
  • java程序:
@Test
public void testNamespace(){
    SqlSession sqlSession = SqlSessionUtil.openSession();
    // 执行sql语句
    // List<Object> cars = sqlSession.selectList("selectAll");
    // 正确完整的写法:namespace.id
    List<Object> cars = sqlSession.selectList("car2.selectAll");
    // 输出结果
    cars.forEach(car -> System.out.println(car));

    sqlSession.commit();
    sqlSession.close();
}

总结笔记

使用mybatis完成CRUD

1. 什么是CRUD
    C: Create增
    R: Retrieve查(检索)
    U: Update改
    D: Delete删

2. insert
    <insert id="insertCar">
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
        values(null,'1003','丰田霸道',30.0,'2000-10-11','燃油车');
    </insert>
    这样写的问题是?
        值 显然是写死到配置文件中的。
        这个在实际开发中是不存在的。
        一定是前端的form表单提交过来数据。然后将值传给sql语句。

    例如:JDBC的代码是怎么写的?
        String sql = "insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)";
        ps.setString(1, xxx);
        ps.setString(2, yyy);
        ....

    在JDBC当中占位符采用的是?,在mybatis当中是什么呢?
        和?等效的写法是:#{}
        在mybatis当中不能使用?占位符,必须使用 #{} 来代替JDBC当中的 ?
        #{} 和 JDBC当中的 ? 是等效的。

    java程序中使用Map可以给SQL语句的占位符传值:
        Map<String, Object> map = new HashMap<>();
        map.put("k1", "1111");
        map.put("k2", "比亚迪汉");
        map.put("k3", 10.0);
        map.put("k4", "2020-11-11");
        map.put("k5", "电车");

        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{k1},#{k2},#{k3},#{k4},#{k5});
        注意:#{这里写什么?写map集合的key,如果key不存在,获取的是null}

        一般map集合的key起名的时候要见名知意。
            map.put("carNum", "1111");
            map.put("brand", "比亚迪汉2");
            map.put("guidePrice", 10.0);
            map.put("produceTime", "2020-11-11");
            map.put("carType", "电车");

            insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType});

    java程序中使用POJO类给SQL语句的占位符传值:
        Car car = new Car(null, "3333", "比亚迪秦", 30.0, "2020-11-11", "新能源");

        注意:占位符#{},大括号里面写:pojo类的属性名
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
        values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})

        把SQL语句写成这个德行:
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
                values(null,#{xyz},#{brand},#{guidePrice},#{produceTime},#{carType})
        出现了什么问题呢?
            There is no getter for property named 'xyz' in 'class com.powernode.mybatis.pojo.Car'
            mybatis去找:Car类中的getXyz()方法去了。没找到。报错了。

        怎么解决的?
            可以在Car类中提供一个getXyz()方法。这样问题就解决了。

        通过这个测试,得出一个结论:
            严格意义上来说:如果使用POJO对象传递值的话,#{}这个大括号中到底写什么?
                写的是get方法的方法名去掉get,然后将剩下的单词首字母小写,然后放进去。
                例如:getUsername() --> #{username}
                例如:getEmail() --> #{email}
                ....
        也就是说mybatis在底层给?传值的时候,先要获取值,怎么获取的?
            调用了pojo对象的get方法。例如:car.getCarNum(),car.getCarType(),car.getBrand()
3. delete
    * 需求:根据id删除数据
        将id=59的数据删除。

    实现:
        int count = sqlSession.delete("deleteById", 59);
        <delete id="deleteById">
            delete from t_car where id = #{fdsfd}
        </delete>
        注意:如果占位符只有一个,那么#{}的大括号里可以随意。但是最好见名知意。

4. update
    * 需求:根据id修改某条记录。

    实现:
        <update id="updateById">
            update t_car set
                 car_num=#{carNum},
                 brand=#{brand},
                 guide_price=#{guidePrice},
                 produce_time=#{produceTime},
                 car_type=#{carType}
            where
                id = #{id}
        </update>

        Car car = new Car(4L, "9999", "凯美瑞", 30.3, "1999-11-10", "燃油车");
        int count = sqlSession.update("updateById", car);

5. select(查一个,根据主键查询的话,返回的结果一定是一个。)
    * 需求:根据id查询。

    实现:
        <select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
            select * from t_car where id = #{id}
        </select>

        Object car = sqlSession.selectOne("selectById", 1);

    需要特别注意的是:
        select标签中resultType属性,这个属性用来告诉mybatis,查询结果集封装成什么类型的java对象。你需要告诉mybatis。
        resultType通常写的是:全限定类名。

    Car{id=1, carNum='null', brand='宝马520Li', guidePrice=null, produceTime='null', carType='null'}
    输出结果有点不对劲:
        id和brand属性有值。
        其他属性为null。

    carNum以及其他的这几个属性没有赋上值的原因是什么?
        select * from t_car where id = 1
        执行结果:
        +----+---------+-----------+-------------+--------------+----------+
        | id | car_num | brand    | guide_price | produce_time | car_type |
        +----+---------+-----------+-------------+--------------+----------+
        |  1 | 1001   | 宝马520Li |     10.00 | 2020-10-11   | 燃油车  |
        +----+---------+-----------+-------------+--------------+----------+
        car_num、guide_price、produce_time、car_type这是查询结果的列名。
        这些列名和Car类中的属性名对不上。
        Car类的属性名:
        carNum、guidePrice、produceTime、carType

        那这个问题怎么解决呢?
            select语句查询的时候,查询结果集的列名是可以使用as关键字起别名的。

        <select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
            select
                id,car_num as carNum,brand,guide_price as guidePrice,
                produce_time as produceTime,
                car_type as carType
            from
                t_car
            where
                id = #{id}
        </select>
        起别名之后:
        +----+--------+-----------+------------+-------------+---------+
        | id | carNum | brand    | guidePrice | produceTime | carType |
        +----+--------+-----------+------------+-------------+---------+
        |  1 | 1001  | 宝马520Li  |     10.00| 2020-10-11 | 燃油车  |
        +----+--------+-----------+------------+-------------+---------+



6. select(查所有的)

    <select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
        select
            id,car_num as carNum,brand,guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
        from
            t_car
    </select>

    List<Object> cars = sqlSession.selectList("selectAll");

    注意:resultType还是指定要封装的结果集的类型。不是指定List类型,是指定List集合中元素的类型。
    selectList方法:mybatis通过这个方法就可以得知你需要一个List集合。它会自动给你返回一个List集合。

7. 在sql mapper.xml文件当中有一个namespace,这个属性是用来指定命名空间的。用来防止id重复。
怎么用?
    在xml文件中:
        <mapper namespace="aaaaaaaaa">
            <select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
                select
                    id,car_num as carNum,brand,guide_price as guidePrice,
                    produce_time as produceTime,
                    car_type
                from
                    t_car
            </select>
        </mapper>
    在java程序中的写法:
        List<Object> cars = sqlSession.selectList("aaaaaaaaa.selectAll");

    实际上,本质上,mybatis中的sqlId的完整写法:
        namespace.id

四、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>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="CarMapper.xml"/>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
  • configuration:根标签,表示配置信息。

  • environments:环境(多个),以“s”结尾表示复数,也就是说mybatis的环境可以配置多个数据源。

    • default属性:表示默认使⽤的是哪个环境,default后⾯填写的是environment的id。default的值只需要和environment的id值⼀致即可。
  • environment:具体的环境配置(主要包括:事务管理器的配置 + 数据源的配置)

    • id:给当前环境⼀个唯⼀标识,该标识⽤在environments的default后⾯,⽤来指定默认环境的选择。
  • transactionManager:配置事务管理器

    • type属性:指定事务管理器具体使⽤什么⽅式,可选值包括两个

      • JDBC:使⽤JDBC原⽣的事务管理机制。底层原理:事务开启

        conn.setAutoCommit(false);开启事务

        …处理业务…

        conn.commit(); 事务提交

      • MANAGED:交给其它容器来管理事务,⽐如WebLogic、JBOSS等。如果没有管理事务的 容器,则没有事务。没有事务的含义:只要执⾏⼀条DML语句,则提交⼀次。

  • dataSource:指定数据源

    • type属性:⽤来指定具体使⽤的数据库连接池的策略,可选值包括三个
      • UNPOOLED:采⽤传统的获取连接的⽅式,虽然也实现Javax.sql.DataSource接⼝,但是 并没有使⽤池的思想。
        • property可以是:
          • driver 这是 JDBC 驱动的 Java 类全限定名。
          • url 这是数据库的 JDBC URL 地址。
          • username 登录数据库的⽤户名。
          • password 登录数据库的密码。
          • defaultTransactionIsolationLevel 默认的连接事务隔离级别。
          • defaultNetworkTimeout 等待数据库操作完成的默认⽹络超时时间(单位:毫秒)
      • POOLED:采⽤传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现。
        • property可以是(除了包含UNPOOLED中之外):
          • poolMaximumActiveConnections 在任意时间可存在的活动(正在使⽤)连接数量,默认值:10
          • poolMaximumIdleConnections 任意时间可能存在的空闲连接数。
          • 其它…
      • JNDI:采⽤服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不⼀样。如果不是web或者maven的war⼯程,JNDI是不能使⽤的。
        • property可以是(最多只包含以下两个属性):
          • initial_context 这个属性⽤来在 InitialContext 中寻找上下⽂(即, initialContext.lookup(initial_context))这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。
          • data_source 这是引⽤数据源实例位置的上下⽂路径。提供了 initial_context 配置时会 在其返回的上下⽂中进⾏查找,没有提供时则直接在 InitialContext 中查找。
  • mappers:在mappers标签中可以配置多个sql映射⽂件的路径。

  • mapper:配置某个sql映射⽂件的路径

    • resource属性:使⽤相对于类路径的资源引⽤⽅式
    • url属性:使⽤完全限定资源定位符(URL)⽅式

4.1 environment

  • mybatis-config.xml文件:
<?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>

    <environments default="powernode">
        <environment id="powernode">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

        <environment id="mybatis">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="CarMapper.xml"/>
    </mappers>
</configuration>
  • Mapper文件:
<?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">

<mapper namespace="car">

    <insert id="insertCarByPOJO" parameterType="com.powernode.mybatis.pojo.Car">
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
        values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    </insert>

</mapper>
  • java程序:
@Test
public void testEnvironment() throws Exception{
    // 获取SqlSessionFactory对象(采用默认的方式获取)
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    // 这种方式就是获取的默认环境
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 执行sql
    int count = sqlSession.insert("car.insertCar");
    System.out.println("插入了几条数据:" + count);
    // 提交事务,关闭资源
    sqlSession.commit();
    sqlSession.close();

    SqlSessionFactory sqlSessionFactory1 = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
    SqlSession sqlSession1 = sqlSessionFactory1.openSession();
    // 执行sql
    count = sqlSession1.insert("car.insertCar");
    System.out.println("插入了几条数据:" + count);
    // 提交事务,关闭资源
    sqlSession1.commit();
    sqlSession1.close();

}
  • 课堂笔记
    • default表示默认使用的环境。
    • 默认环境什么意思?当你使用mybatis创建SqlSessionFactory对象的时候,没有指定环境的话,默认使用哪个环境。
    • 其中的一个环境。连接的数据库是powernode
    • 一般一个数据库会对应一个SqlSessionFactory对象。
    • 一个环境environment会对应一个SqlSessionFactory对象

4.2 transactionManager

  • transactionManagertypeMANAGED时:

    • Mapper文件:
    <?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">
    
    <mapper namespace="car">
    
        <insert id="insertCarByPOJO" parameterType="com.powernode.mybatis.pojo.Car">
            insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
            values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
        </insert>
    
    </mapper>
    
    • java程序:
    @Test
    public void testTransactionManager() throws IOException {
        Car car = new Car();
        car.setCarNum("133");
        car.setBrand("丰田霸道");
        car.setGuidePrice(50.3);
        car.setProduceTime("2020-01-10");
        car.setCarType("燃油车");
    
        // 获取SqlSessionFactory对象(采用默认的方式获取)
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 这种方式就是获取的默认环境
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "mybatis");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行sql
        int count = sqlSession.insert("car.insertCarByPOJO", car);
        System.out.println("插入了几条数据:" + count);
        // 提交事务,关闭资源
        //        sqlSession.commit();
        sqlSession.close();
    }
    
    • 交给容器去管理事务,但⽬前使⽤的是本地程序,没有容器的⽀持,当mybatis找不到容器的⽀持时:没有事务。也就是说只要执⾏⼀条DML语句,则提交⼀次
  • 当事务管理器是:JDBC

    • 采⽤JDBC的原⽣事务机制:

      开启事务:conn.setAutoCommit(false);

      …处理业务…

      提交事务:conn.commit();

  • 课堂笔记

    • transactionManager标签:
    1. 作用:配置事务管理器。指定mybatis具体使用什么方式去管理事务。
    2. type属性有两个值:
      第一个:JDBC: 使用原生的JDBC代码来管理事务。
      conn.setAutoCommit(false);

      conn.commit();
      第二个:MANAGED:mybatis不再负责事务的管理,将事务管理交给其它的JEE(JavaEE)容器来管理。例如:spring
    3. 大小写无所谓。不缺分大小写。但是不能写其他值。只能是二选一:
      jdbc、managed
    4. 在mybatis中提供了一个事务管理器接口:Transaction
      该接口下有两个实现类:
      JdbcTransaction
      ManagedTransaction
      如果type=“JDBC”,那么底层会实例化JdbcTransaction对象。
      如果type=“MANAGED”,那么底层会实例化ManagedTransaction

4.3 dataSource

  • type 可选有三种
    • UNPOOLED
    • POOLED
    • JNDI
  • dataSource配置:
  1. dataSource被称为数据源。

  2. dataSource作用是什么?为程序提供Connection对象。(但凡是给程序提供Connection对象的,都叫做数据源。)

  3. 数据源实际上是一套规范。JDK中有这套规范:javax.sql.DataSource(这个数据源的规范,这套接口实际上是JDK规定的。)

  4. 我们自己也可以编写数据源组件,只要实现javax.sql.DataSource接口就行了。实现接口当中所有的方法。这样就有了自己的数据源。
    比如你可以写一个属于自己的数据库连接池(数据库连接池是提供连接对象的,所以数据库连接池就是一个数据源)。

  5. 常见的数据源组件有哪些呢【常见的数据库连接池有哪些呢】?
    阿里巴巴的德鲁伊连接池:druid
    c3p0
    dbcp

  6. type属性用来指定数据源的类型,就是指定具体使用什么方式来获取Connection对象:
    type属性有三个值:必须是三选一。
    type=“[UNPOOLED|POOLED|JNDI]”
    UNPOOLED:不使用数据库连接池技术。每一次请求过来之后,都是创建新的Connection对象。
    POOLED:使用mybatis自己实现的数据库连接池。
    JNDI:集成其它第三方的数据库连接池。

  7. JNDI是一套规范。谁实现了这套规范呢?大部分的web容器都实现了JNDI规范:
    例如:Tomcat、Jetty、WebLogic、WebSphere,这些服务器(容器)都实现了JNDI规范。
    JNDI是:java命名目录接口。Tomcat服务器实现了这个规范。

  • 这种再重点说⼀下type="POOLED"的时候,它的属性有哪些?

    <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}"/>
        <!--提醒:正常使用连接池的话,池中有很多参数是需要设置的。设置好参数,可以让连接池发挥的更好。事半功倍的效果。-->
        <!--具体连接池当中的参数如何配置呢?需要反复的根据当前业务情况进行测试。-->
        <!--poolMaximumActiveConnections:连接池当中最多的正在使用的连接对象的数量上限。最多有多少个连接可以活动。默认值10-->
        <property name="poolMaximumActiveConnections" value="10"/>
        <!--每隔2秒打印日志,并且尝试获取连接对象-->
        <property name="poolTimeToWait" value="2000"/>
        <!--强行让某个连接空闲,超时时间的设置-->
        <property name="poolMaximumCheckoutTime" value="10000"/>
        <!--最多的空闲数量-->
        <property name="poolMaximumIdleConnections" value="5"/>
    </dataSource>
    
    • poolMaximumActiveConnections:最⼤的活动的连接数量。默认值10

      • 最⼤的活动的连接数量就是连接池连接数量的上限。
      • 默认值10,如果有10个请求正在使⽤这10个连接, 第11个请求只能等待空闲连接。
    • poolMaximumIdleConnections:最⼤的空闲连接数量。默认值5

      • 如果已经有了5个空闲连接,当第6个连接要空闲下来的时候,连接池会选择关闭该连接对象,来减少数据库的开销。
    • poolMaximumCheckoutTime:强⾏回归池的时间。默认值20秒。

    • poolTimeToWait:当⽆法获取到空闲连接时,每隔20秒打印⼀次⽇志,避免因代码配置有误,导致傻等。(时⻓是可以配置的)

    • 需要根据系统的并发情况,来合理调整连接池最⼤连接数以及最多空闲数量。充分发挥数据库连接池的 性能。

      当然,还有其他属性。对于连接池来说,以上几个属性⽐较重要。

  • 测试一下:

    • mybatis-config.xml文件:
    <?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>
    
        <environments default="powernode">
            <environment id="powernode">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                    <!--提醒:正常使用连接池的话,池中有很多参数是需要设置的。设置好参数,可以让连接池发挥的更好。事半功倍的效果。-->
                    <!--具体连接池当中的参数如何配置呢?需要反复的根据当前业务情况进行测试。-->
                    <!--poolMaximumActiveConnections:连接池当中最多的正在使用的连接对象的数量上限。最多有多少个连接可以活动。默认值10-->
                    <property name="poolMaximumActiveConnections" value="3"/>
                    <!--每隔2秒打印日志,并且尝试获取连接对象-->
                    <property name="poolTimeToWait" value="2000"/>
                    <!--强行让某个连接空闲,超时时间的设置-->
                    <property name="poolMaximumCheckoutTime" value="10000"/>
                    <!--最多的空闲数量-->
                    <property name="poolMaximumIdleConnections" value="5"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="CarMapper.xml"/>
        </mappers>
    </configuration>
    
    • Mapper文件:
    <?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">
    
    <mapper namespace="car">
    
        <insert id="insertCar">
            insert into t_car values(null,'8888','沃尔沃',30.0,'2000-11-11','燃油车')
        </insert>
    
    </mapper>
    
    • java程序:
    @Test
    public void testDataSource() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // sqlSessionFactory对象:一个数据一个。不要频繁创建该对象。
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
    
        /*// 通过sqlSessionFactory对象可以开启多个会话。
            // 会话1
            SqlSession sqlSession1 = sqlSessionFactory.openSession();
            sqlSession1.insert("car.insertCar");
            sqlSession1.commit();
            sqlSession1.close(); // 因为要测试连接池的效果,关闭是需要的。别忘了,要不然测不出来。
    
            // 会话2
            SqlSession sqlSession2 = sqlSessionFactory.openSession();
            sqlSession2.insert("car.insertCar");
            sqlSession2.commit();
            sqlSession2.close();*/
        SqlSession sqlSession = null;
        // 设置最大连接为3,所以调用4个连接时会出现等待现象
        for (int i = 0; i < 4; i++) {
            sqlSession = sqlSessionFactory.openSession();
            sqlSession.insert("car.insertCar");
            // 不要关闭。
        }
        sqlSession.close();
        // 由于没有提交事务,所以数据库无变化
    }
    
    • 测试连接池:

在这里插入图片描述

在这里插入图片描述

  • 连接池图示
    在这里插入图片描述

4.4 properties

  • mybatis提供了更加灵活的配置,连接数据库的信息可以单独写到⼀个属性资源⽂件中.

  • java.util.Properties类。是一个Map集合。key和value都是String类型

    • 在properties标签中可以配置很多属性
    <properties>
        <!--这是其中的一个属性-->
        <!--<property name="属性名" value="属性值"/>-->
        <property name="jdbc.username" value="root"/>
        <property name="jdbc.password" value="root"/>
    </properties>
    
    • 通过文件的方式导入properties信息
    <!--resource,一定是从类路径下开始查找资源-->
    <properties resource="jdbc.properties" />
    
    <!--从绝对路径当中加载资源。绝对路径怎么写?file:///路径-->
    <properties url="file:///d:/jdbc.properties" />
    
  • 假设在类的根路
    径下创建jdbc.properties⽂件,配置如下:

jdbc.username=root
jdbc.password=root
  • 在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>
	<!--resource,一定是从类路径下开始查找资源-->
    <properties resource="jdbc.properties" />
    
    <environments default="powernode">
        <environment id="powernode">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
        <mapper resource="CarMapper.xml"/>
    </mappers>
</configuration>
  • Mapper文件:
<?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">

<mapper namespace="car">

    <insert id="insertCar">
        insert into t_car values(null,'8888','沃尔沃',30.0,'2000-11-11','燃油车')
    </insert>

</mapper>
  • java程序:
@Test
public void testProperties(){
    SqlSession sqlSession = SqlSessionUtil.openSession();
    // 执行sql
    int count = sqlSession.insert("car.insertCar");
    System.out.println("插入了几条记录:" + count);

    sqlSession.commit();
    sqlSession.close();
}
  • 注意:如果不知道mybatis-config.xml⽂件中标签的编写顺序的话,可以有两种⽅式知道它的顺序:
    • 第⼀种⽅式:查看dtd约束⽂件。
    • 第⼆种⽅式:通过idea的报错提示信息。【⼀般采⽤这种⽅式】

4.5 mapper

  • mapper标签⽤来指定SQL映射⽂件的路径,包含多种指定⽅式,这⾥先主要看其中两种:
  • 第⼀种:resource,从类的根路径下开始加载【比url常⽤】
<mappers>
    <mapper resource="CarMapper.xml"/>
</mappers>

如果是这样写的话,必须保证类的根下有CarMapper.xml⽂件。

如果类的根路径下有⼀个包叫做test,CarMapper.xml如果放在test包下的话,这个配置应该是这样写:

<mappers>
    <mapper resource="test/CarMapper.xml"/>
</mappers>
  • 第⼆种:url,从指定的url位置加载

    假设CarMapper.xml⽂件放在d盘的根下,这个配置就需要这样写:

<mappers>
    <mapper url="file:///d:/CarMapper.xml" />
</mappers>

[To be continue…]

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值