一、数据准备

二、开发步骤
1、引入依赖
<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.15</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.2.0</version>
    </dependency>
</dependencies>2、编写核心配置文件: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>
    <!--
        允许设置多个环境,但是每个 SqlSessionFactory 实例只能选择一种环境
        设置默认的环境:development
    -->
    <environments default="development">
        <!-- 环境配置,名称为:development -->
        <environment id="development">
            <!-- 配置事物管理器为 JDBC -->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 配置数据库连接信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb"/>
                <property name="username" value="root"/>
                <property name="password" value="mysql"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!-- 指定 XxxMapper.xml 文件 -->
        <mapper resource="CarMapper.xml"/>
    </mappers>
</configuration>3、编写 XxxMapper.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="qiuXuan">
    <!--id就代表了下面的这条sql语句-->
    <insert id="insertCar">
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
        values(null,'1003','五菱宏光',30.0,'2020-09-18','燃油车');
    </insert>
</mapper>4、在 mybatis-config.xml 文件中指定 XxxMapper.xml 文件的路径
5、编写 MyBatis 程序
-  在 MyBatis 当中 SqlSession 负责 SQL 语句的执行,是 Java 程序与数据库之间的会话 
-  要获取 SqlSession 对象,需要先获取 SqlSessionFactory 对象,通过 SqlSessionFactory 工厂来生产 SqlSession 对象 
如何获取 SqlSessionFactory 对象?
通过 SqlSessionFactoryBuilder 对象的 build 方法获取一个 SqlSessionFactory 对象
SqlSessionFactoryBuilder ---> SqlSessionFactory ---> SqlSession
package com.qiuxuan;
public class MyBatisIntroductionTest {
    public static void main(String[] args) throws IOException {
        // 获取 SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        /**
         * 获取 SqlSessionFactory
         *
         * build 方法的参数为一个 InputStream
         * 指向 mybatis-config.xml 核心配置文件
         *
         * 可以通过 MyBatis 的 Resources 工具类获取
         * 其 getResourceAsStream 方法返回的就是一个 InputStream
         * 参数为核心配置文件路径(默认从类根路径[resources]查找资源)
         */
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = builder.build(is);
        // 获取 SqlSession
        SqlSession sqlSession = factory.openSession();
        // 执行 SQL 语句(参数为 SQL 语句的 id)
        int count = sqlSession.insert("insertCar");
        System.out.println(count);
        // mybatis 默认是不会自动提交的,需要手动提交
        sqlSession.commit();
    }
}三、MyBatis 中有两个主要的配置文件
-  mybatis-config.xml(一个) -  核心配置文件,主要配置连接数据库的信息等 
 
-  
-  XxxMapper.xml(一个表一个) -  用于编写 SQL 语句的配置文件 
 
-  
四、Tips
mybatis 中 sql 语句的结尾 “;” 可以省略
使用 Resources.getResourceAsStream 获取资源文件的方式符合 OCP 原则,有利于程序的移植性、健壮性
若使用 FileInputStream 方式获取资源文件,当程序需要在其他系统运行时,原来的路径将会失效,需要修改 Java 代码中的资源路径,违背了 OCP 原则
也可使用类加载器获取资源:
ClassLoader.getSystemClassLoader().getResourceAsStream("资源路径");与 Resources.getResourceAsStream 一致,都是从根路径获取资源,即 resources 目录下
ClassLoader.getSystemClassLoader() 获取的是系统类加载器,而 Resources.getResourceAsStream 底层使用的就是 ClassLoader.getSystemClassLoader()
五、MyBatis 的事务管理机制
在 mybatis-config.xml 文件中,可以通过以下的配置进行 mybatis 的事务管理
<transactionManager type="JDBC"/>type 属性包括两个值:JDBC、 MANAGED,对应两种事务管理机制
-  JDBC 事务管理器 -  MyBatis 框架自己采用管理事务,自己采用原生的 JDBC 代码去管理事务 
-  使用 JDBC 事务管理器底层创建事务管理对象的是 JdbcTransation 对象 
 
-  
conn.setAutoCommit(false);开启事务若使用 JDBC 事务管理器,在
factory.openSession()底层会执行此语句若使用
factory.openSession()时传入参数 true,则底层不会执行conn.AutoCommit(false),也就不会开启事务,此时执行任意 DML 语句都会自动提交业务处理...
conn.commit();提交事务
-  MANAGED 事务管理器 -  mybatis 不再负责事务的管理了,事务管理交给其他容器负责,例如:Spring 
 
-  
六、较完整的 MyBatis 程序
package com.qiuxuan;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisCompleteCodeTest {
    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 (Exception e) {
            // 回滚
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            e.printStackTrace();
        } finally {
            // 6.关闭
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}七、Junit 单元测试
JUnit 是专门做单元测试的组件。
-  在实际开发中,单元测试一般是由我们 Java 程序员来完成的。 -  要对自己写的每一个业务方法负责任,要保证每个业务方法在进行测试的时候都能通过。 
 
-  
-  测试的过程中涉及到两个概念: -  期望值 
-  实际值 
 
-  
-  期望值和实际值相同表示测试通过,期望值和实际值不同则单元测试执行时会报错。 
1、引入依赖
<!-- junit依赖 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>2、编写单元测试类【测试用例】
测试用例中每一个测试方法上使用 @Test 注解进行标注。
测试用例的名字以及每个测试方法的定义都是有规范的:
-  测试用例的名字: XxxTest
-  测试方法声明格式: public void test业务方法名(){}
// 测试用例
public class CarMapperTest{
    
    // 测试方法
    @Test
    public void testInsert(){}
    
    @Test
    public void testUpdate(){}
    
}可以在类上执行,也可以在方法上执行
-  在类上执行时,该类中所有的测试方法都会执行。 
-  在方法上执行时,只执行当前的测试方法。 
-  编写一个测试用例,来测试 insertCar 业务 
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 (Exception e) {
            // 回滚
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            e.printStackTrace();
        } finally {
            // 6.关闭
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}八、logback 日志框架
-  引入日志框架的目的是为了看清楚 mybatis 执行的具体 sql。 
-  启用标准日志组件,只需要在 mybatis-config.xml 文件中添加以下配置:【可参考 mybatis 手册】 
mybatis-config.xml
<settings>
  <setting name="logImpl" value="STDOUT_LOGGING" />
</settings>注意:<configuration> 里配置的位置是有顺序要求的,否则会报错
Error creating document instance. Cause: org.xml.sax.SAXParseException;
<configuration>
    <properties>...</properties>
    <settings>...</settings>
    <typeAliases>...</typeAliases>
    <typeHandlers>...</typeHandlers>
    <objectFactory>...</objectFactory>
    <objectWrapperFactory>...</objectWrapperFactory>
    <reflectorFactory>...</reflectorFactory>
    <plugins>...</plugins>
    <environments>...</environments>
    <databaseIdProvider>...</databaseIdProvider>
    <mappers>...</mappers>
</configuration>标准日志也可以用,但是配置不够灵活,可以集成其他的日志组件,例如:log4j,logback等。
-  logback 是目前日志框架中性能较好的,较流行的,所以选它。 
-  引入 logback 相关依赖 
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.11</version>
  <scope>test</scope>
</dependency>-  引入 logback 相关配置文件(文件名叫做 logback.xml 或 logback-test.xml,放到类路径当中) 
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!-- 控制台输出 -->
    <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 %logger{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>九、MyBatis 工具类 SqlSessionUtil 的封装
每一次获取 SqlSession 对象代码太繁琐,封装一个工具类
/**
 * MyBatis工具类
 *
 * @author 秋玄
 * @version 1.0.0
 * @since 1.0.0
 */
public class SqlSessionUtil {
    private static final SqlSessionFactory sqlSessionFactory;
    /**
     * 类加载时初始化sqlSessionFactory对象
     */
    static {
        try {
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。
     *
     * @return 新的会话对象
     */
    public static SqlSession openSession() {
        return sqlSessionFactory.openSession(true);
    }
}一 叶 知 秋,奥 妙 玄 心


















