> 文档中心 > 【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序


一、MyBatis概述

1. 框架

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

2. 三层架构

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

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

3. JDBC不⾜

案例一:我们在写JDBC代码时会发现:sql语句是写死的;并且如果对于一个很多字段的表进行insert操作,很有很多繁琐重复的代码

// sql语句写死在java程序中String sql = "insert into t_user(id,idCard,username,password,birth,gender,email,city,street,zipcode,phone,grade) values(?,?,?,?,?,?,?,?,?,?,?,?)";PreparedStatement ps = conn.prepareStatement(sql);// 繁琐的赋值:思考⼀下,这种有规律的代码能不能通过反射机制来做⾃动化。ps.setString(1, "1");ps.setString(2, "123456789");ps.setString(3, "zhangsan");ps.setString(4, "123456");ps.setString(5, "1980-10-11");ps.setString(6, "男");ps.setString(7, "zhangsan@126.com");ps.setString(8, "北京");ps.setString(9, "⼤兴区凉⽔河⼆街");ps.setString(10, "1000000");ps.setString(11, "16398574152");ps.setString(12, "A");// 执⾏SQLint count = ps.executeUpdate();// ......

案例二:在执行查询语句时,对于结果集的数据遍历获取到过程是很繁琐的,并且我们如果还需要给获取到的数据封装到对象里,也是一个繁琐的过程

// sql语句写死在java程序中String sql = "select id,idCard,username,password,birth,gender,email,city,street,zipcode,phone,grade from t_user";PreparedStatement ps = conn.prepareStatement(sql);ResultSet rs = ps.executeQuery();List userList = new ArrayList();// 思考以下循环中的所有代码是否可以使⽤反射进⾏⾃动化封装。while(rs.next()){ // 获取数据 String id = rs.getString("id"); String idCard = rs.getString("idCard"); String username = rs.getString("username"); String password = rs.getString("password"); String birth = rs.getString("birth"); String gender = rs.getString("gender"); String email = rs.getString("email"); String city = rs.getString("city"); String street = rs.getString("street"); String zipcode = rs.getString("zipcode"); String phone = rs.getString("phone"); String grade = rs.getString("grade"); // 创建对象 User user = new User(); // 给对象属性赋值 user.setId(id); user.setIdCard(idCard); user.setUsername(username); user.setPassword(password); user.setBirth(birth); user.setGender(gender); user.setEmail(email); user.setCity(city); user.setStreet(street); user.setZipcode(zipcode); user.setPhone(phone); user.setGrade(grade); // 添加到集合 userList.add(user);}// ......

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

4. 了解MyBatis

(1)MyBatis本质上就是对JDBC的封装,通过MyBatis完成CRUD。
(2)MyBatis在三层架构中负责持久层的,属于持久层框架。
(3)MyBatis的发展历程:
①MyBatis本是apache的⼀个开源项⽬iBatis,2010年这个项⽬由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11⽉迁移到Github。
②iBATIS⼀词来源于“internet”和“abatis”的组合,是⼀个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)。
(4)ORM:对象关系映射
O(Object):Java虚拟机中的 Java对象
R(Relational):关系型数据库
M(Mapping):将Java虚拟机中的Java对象 映射到数据库表中⼀⾏记录,或是将数据库表中⼀⾏记录映射成Java虚拟机中的⼀个Java对象。
(5)MyBatis框架就是一个ORM框架:
MyBatis是一个半自动化的ORM,因为MyBatis框架中SQL语句是需要程序员自己编写的
Hibernate框架是一个全自动化的ORM,使用Hibernate框架的时候不需要程序员手动编写SQL语句,SQL语句可以自动生成。

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序 【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

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

二、MyBatis⼊⻔程序

    • MyBatis下载

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

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序 【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

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

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

通过以上解压可以看到,框架⼀般都是以jar包的形式存在,我们接下来学习mybatis使⽤maven,所以这个jar我们不需要。

2. MyBatis⼊⻔程序开发步骤

2.1 数据库表的设计

准备数据库表:汽⻋表t_car,字段包括:
①id:主键(⾃增)【bigint】
②car_num:汽⻋编号【varchar】
③brand:品牌【varchar】
④guide_price:⼚家指导价【decimal类型,专⻔为财务数据准备的类型】
⑤produce_time:⽣产时间【char,年⽉⽇即可,10个⻓度,例如:'2022-10-11'】
⑥car_type:汽⻋类型(燃油⻋、电⻋、氢能源)【varchar】

使⽤navicat for mysql⼯具建表

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

使⽤navicat for mysql⼯具向t_car表中插⼊两条数据,如下:

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

2.2 配置Maven环境

(1)选择JDK

File->Project Structure->Project

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

(2)设置自己的Maven

file--settings ---Build, Excution,Deployment--Build Tools--Maven

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

2.3 入门程序步骤

(1)resources目录

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

(2)开发步骤

第一步: 打包方式jar:jar
第二步: 引入依赖:mybatis依赖 和mysql驱动依赖,从远程仓库 mvnrepository.com中查找

           org.mybatis     mybatis     3.5.10        mysql     mysql-connector-java     5.1.23     

查看中文文档 https://mybatis.net.cn/ ,了解接下来的步骤;从 XML 中构建 SqlSessionFactory,通过阅读官方文档这句话,可以得到:
①在MyBatis中一定是有一个很重要的对象,这个对象是:SqlSessionFactory对象。
②SqlSessionFactory对象的创建需要XML(一个配置文件,从官方文档复制)。
第三步:编写mybatis核心配置文件:mybatis-config.xml
注意:①这个文件名不是必须叫做mybatis-config.xml,只是大家都采用这个名字。
②这个文件存放的位置可以随意,但一般情况下,会放到类的根路径下(resources目录下)。

                                          

mybatis中实际上有两个主要的配置文件:
其中一个是:mybatis-config.xml,这是核心配置文件,主要配置连接数据库的信息等。(一个)
另一个是:XxxxMapper.xml,这个文件是专门用来编写SQL语句的配置文件。(一个表一个)
例如:t_user表,一般会对应一个UserMapper.xml
t_student表,一般会对应一个StudentMapper.xml
第四步:编写XxxxMapper.xml文件,在这个配置文件当中编写SQL语句!
这个文件放的位置也不是固定,这里给它起个名字,叫做:CarMapper.xml,把它暂时放到类的根路径下。

              insert into t_car(id,car_num,id,guide_price,produce,car_type)      values(null,'1003','丰田',30.0,'2020-10-11','燃油车')    

第五步:在核心配置文件mybatis-config.xml文件中指定XxxxMapper.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

package com.bjpowernode.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 javax.annotation.Resource;import java.io.InputStream;public class MyBatisIntroductionTest {    public static void main(String[] args) throws Exception{ // 1、获取SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 2、获取SqlSessionFactory对象 // 需要一个指向核心配置文件mybatis-config.xml的io流 InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); // 一般情况下:一个数据库对应一个SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); // 3、获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 4、执行sql语句 // 参数是sql语句的id int count = sqlSession.insert("insertCar"); System.out.println("插入了"+count+"数据"); // 5、需要手动提交 sqlSession.commit();    }}

执行结果:正常插入数据

【MyBatis】| MyBatis概述、MyBatis⼊⻔程序

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

(3)Mybatis的事务管理机制深度剖析

①在mybatis-config.xml文件中,可以通过以下的配置进行mybatis的事务管理

type属性的值包括两个:JDBC(jdbc)、MANAGED(managed),不区分大小写。
②在mybatis中提供了两种事务管理机制:
第一种:JDBC事务管理器
第二种:MANAGED事务管理器
③JDBC事务管理器:
mybatis框架自己管理事务,自己采用原生的JDBC代码去管理事务;
获取SqlSession对象时,SqlSession sqlSession = sqlSessionFactory.openSession(); 如果使用事务管理器JDBC,底层实际上会执行:conn.setAutoCommit(false);
手动提交sqlSession.commit(); 如果使用事务管理器JDBC,底层实际上会执行conn.commit()
④使用JDBC事务管理器的话,底层创建的事务管理器对象:JdbcTransaction对象。但是如果编写代码:SqlSession sqlSession = sqlSessionFactory.openSession(true);传了参数true表示没有开启事务;因为这种方式压根不会执行:conn.setAutoCommit(false)!
⑤在JDBC事务中,如果没有执行conn.setAutoCommit(false);那么autoCommit就是true。如果autoCommit是true,就表示没有开启事务,只要执行任意一条DML语句就提交一次!
⑥MANAGED事务管理器:
mybatis不再负责事务的管理了,事务管理交给其它容器来负责,例如:spring。对于我们当前的单纯的只有mybatis的情况下,如果配置为:MANAGED,那么表示事务这块是没人管的,没有人管理事务表示事务压根没有开启,自己执行一条语句就会自动提交。
注意:只要你的autoCommit是true,就表示没有开启事务;只有你的autoCommit是false的时候,才表示开启了事务!

(4)第一个完整的MyBatis程序

package com.bjpowernode.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;/** * @Author:朗朗乾坤 * @Package:com.bjpowernode.mybatis.test * @Project:mybatis * @name:MybatisCompleteTest * @Date:2022/12/28 20:36 */public class MybatisCompleteTest {    public static void main(String[] args) { SqlSession sqlSession = null; try {     // SqlSessionFactoryBuilder     SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();     // 获取SqlSessionFactory对象     SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsReader("mybatis-config.xml"));     // 获取SqlSession对象(开启事务)     sqlSession = sqlSessionFactory.openSession();     // 执行sql     int count = sqlSession.insert("insertCar");     if (count == 1){  System.out.println("成功插入数据");     }     // 提交事务(事务提交)     sqlSession.commit(); } catch (IOException e) {     // 回滚事务     if (sqlSession != null) {  sqlSession.rollback();     }     e.printStackTrace(); } finally {     // 关闭会话     if (sqlSession != null) {  sqlSession.close();     } }    }}

(5)使用junit插件进行单元测试

①先在pom.xml当中引入单元测试的依赖
②测试的类名:测试的类名+Test
③测试方法的方法名:以test开始;假设测试的方法是sum,这个测试方法名:testSum
④加上@Test注解,@Test注解非常重要,被这个注解标注的方法就是一个单元测试方。
⑤单元测试中有两个重要的概念:
一个是:实际值(被测试的业务方法的真正执行结果)
一个是:期望值(执行了这个业务方法之后,你期望的执行结果是多少)
⑥加断言进行测试,Assert.assertEquals(期望值, 实际值);

                junit     junit     4.12     test 

⑦当我们有多个类要测试的话,如果使用上述main方法的形式,就需要写很多个类,多个main方法,比较麻烦!所以我们可以使用junit单元测试的形式,只写一个类(在test/java下),通过定义方法来测试,不需要写mian方法也能执行!

package com.bjpowernode.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 testInsert(){ SqlSession sqlSession = null; try {     // SqlSessionFactoryBuilder     SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();     // 获取SqlSessionFactory对象     SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsReader("mybatis-config.xml"));     // 获取SqlSession对象(开启事务)     sqlSession = sqlSessionFactory.openSession();     // 执行sql     int count = sqlSession.insert("insertCar");     if (count == 1){  System.out.println("成功插入数据");     }     // 提交事务(事务提交)     sqlSession.commit(); } catch (IOException e) {     // 回滚事务     if (sqlSession != null) {  sqlSession.rollback();     }     e.printStackTrace(); } finally {     // 关闭会话     if (sqlSession != null) {  sqlSession.close();     } }    }}

2.4 Mybatis集成日志框架logback

(1)mybatis常见的集成的日志组件有哪些呢?
SLF4J(沙拉风):沙拉风是一个日志标准,有一个框架叫做logback,它实现了沙拉风规范。
LOG4J
LOG4J2
STDOUT_LOGGING
....
(2)其中STDOUT_LOGGING是标准日志,mybatis已经实现了这种标准日志;不需要引入任何的依赖,只要开启即可。怎么开启呢?在mybatis-config.xml文件中使用settings标签进行配置开启。
①这个标签在编写的时候要注意,它应该出现在environments标签之前;注意顺序!因为有dtd文件进行约束,我们只要参考dtd约束的范围即可。
②这种实现方式可以看到一些信息,比如:连接对象什么时候创建,什么时候关闭,sql语句是怎样的;但是没有详细的日期,线程名字等。如果想使用更加丰富的配置,可以集成第三方的log组件。

 

(3)集成logback日志框架。
logback日志框架实现了SLF4J标准。(沙拉风:日志文件,日志标准)
①第一步:mybatis-config.xml文件中使用settings标签进行配置SLF4J
注意:也可以不用配,只有使用mybatis内置的日志文件STDOUT_LOGGING,这个才必须要配置!

 

②第二步:引入logback的依赖。

     ch.qos.logback     logback-classic     1.2.11

③第三步:引入logback所必须的xml配置文件。
这个配置文件的名字必须叫做:logback.xml或者logback-test.xml,不能是其它的名字。
这个配置文件必须放到类的根路径下,不能是其他位置。
这个配置文件主要配置日志输出相关的级别以及日志具体的格式。

                           %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n                             <!-- ⽇志输出级别,logback⽇志级别包括五个:TRACE < DEBUG < INFO < WARN           

2.5 MyBatis⼯具类SqlSessionUtil的封装

(1) 工具类的构造方法一般都是私有化的,防止创建对象。
(2)对于SqlSessionFactory对象,一个SqlSessionFactory对应一个environment,一个environment对应一个数据库,所以我们不需要把它放到方法里,应该放到静态代码块里,类加载时获取到qlSessionFactory对象。

package com.bjpowernode.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;/** * @Author:朗朗乾坤 * @Package:com.bjpowernode.mybatis.utils * @Project:mybatis * @name:SqlSessionUtils * @Date:2022/12/29 14:11 */public class SqlSessionUtils {    // 防止创建对象    public SqlSessionUtils() {    }    // 在静态代码块里获取SqlSessionFactory对象    private static SqlSessionFactory sqlSessionFactory;    static { try {     sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")); } catch (IOException e) {     e.printStackTrace(); }    }    // 定义一个方法,获取会话对象    public static SqlSession openSession(){ return sqlSessionFactory.openSession();    }}

(3)使用自己编写的工具类,进行测试

package com.bjpowernode.mybatis.test;import com.bjpowernode.mybatis.utils.SqlSessionUtils;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 testInsertCarByUtil(){ SqlSession sqlSession = SqlSessionUtils.openSession(); int count = sqlSession.insert("insertCar"); System.out.println(count); sqlSession.commit(); sqlSession.close();    }