Mybatis快速入门

1.一条完整的Mybatis使用过程

目录结构:

1.创建数据库和表,并插入数据

CREATE DATABASE `mybatis` /*!40100 DEFAULT CHARACTER SET utf8mb4 */

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4

并插入数据:

2.新建maven项目,添加依赖和插件

新建maven项目(quickstart模板)

添加mybatis依赖

    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.7</version>
    </dependency>
    <!--mysql依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.49</version>
    </dependency>

然后要添加 资源文件的指定

  <!--添加资源文件的锁定-->
  <build>
    <resources>
      <!--锁定java目录下的文件-->
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>

      <!--锁定文件修改之后,需要重新锁定resources下的文件-->
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>
      
    </resources>
  </build>

为什么要添加资源文件的指定?
来测试一下,不添加资源文件指定:
在这
里插入图片描述
先clean以下之前编译结果,测试一下添加资源文件锁定后的编译结果:

3.idea添加数据库可视化操作



4.写jdbc属性文件

jdbc.diverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=admin

5.核心配置文件(配置数据源、jdbc连接参数、注册mapper文件)

SqlMapConfig.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">

核心配置文件内容:

<?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>
    <!--读取属性文件——JDBC.properties
            标签属性:
                resources:从resources目录下找指定文件
                url:使用绝对路径加载指定文件
    -->
    <properties resource="jdbc.properties"></properties>


    <!--配置数据库的环境变量(数据库连接配置)
        标签属性:
            default:指定生效的<environment
            id:对接<environments的default属性
    -->
    <environments default="development">
        <!--开发时使用的数据库配置-->
        <environment id="development">
            <!--配置事务管理器
                type:指定事务管理的方式
                    JDBC:事务的控制交给程序员处理
                    MANAGED:由容器(spring)管理事务
            -->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源
                type:指定不同的配置方式
                    JNDI:java命名目录接口,在服务端进行数据库连接池的管理
                    POOLED:使用数据库连接池
                    UNPOLLED:不使用数据库连接池
            -->
            <dataSource type="POOLED">
                <!--数据库连接的基本参数
                        diver、url、username、password
                -->
                <property name="driver" value="${jdbc.diverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

        <!--本机数据库配置-->
        <environment id="home">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>

        <!--上限数据库配置-->
        <environment id="online">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>
    </environments>
    
    <!--注册mapper文件-->
</configuration>

http://mybatis.org/dtd/mybatis-3-config.dtd 这个文档中规定了此配置文件中可以书写哪些标签

<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>

为什么要用数据库连接池?
在这里插入图片
描述

6.编写数据库实体类

package org.example.pojo;

/**
 * @Description:
 * @Author:cjy
 * @Data:2022/5/3
 * @Version:
 */
public class Student {
    private Integer id;
    private String name;
    private String email;
    private Integer age;

    /*
        无参构造方法
     */
    public Student() {
    }

    /*
        全参的构造方法
     */
    public Student(Integer id, String name, String email, Integer age) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.age = age;
    }

    /*
        不包括主键的构造方法
            做增加操作时,主键不需要给值
     */
    public Student(String name, String email, Integer age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

7.编写映射文件(SQL语句)

StudentMapper.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">

映射文件的内容:

<?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标签:整个文件的标签,用来开始和结束xml文件
    属性:
        namespace:指定命名空间(相当于包名),用来区分不同的mapper
-->

<mapper namespace="test">
    <!--
        完成查询所有学生的功能
        List<Student> getAll——测试类查询
            resultType:指定查询返回结果集的类型(全限定名),如果是集合,则必须是泛型的类型
            parameterType:方法中有参数,则需要此属性指定参数的类型
    -->
    <select id="getAll" resultType="org.example.pojo.Student">
        /*不使用*查询,因为*查询的效率极低*/
        select id,name,email,age
        from student
    </select>
</mapper>

注意: 写完了映射文件之后,是无法直接使用映射文件的,还需要去核心配置文件中注册!!

在核心文件中注册:

    <!--注册mapper文件
        resource:从resources目录下找到指定的文件加载
        url:使用绝对路径注册
        class:动态代理方式下载注册
    -->
    <mappers>
        <mapper resource="StudentMapper.xml"></mapper>
    </mappers>
</configuration>

http://mybatis.org/dtd/mybatis-3-mapper.dtd 这个文档中规定了此映射文件中可以书写哪些标签

<!ELEMENT mapper (cache-ref | cache | resultMap* | parameterMap* | sql* | insert* | update* | delete* | select* )+>

8.测试类

package org.example;

public class AppTest 
{
    @Test
    public void test() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        List<Student> list = sqlSession.selectList("test.getAll");
        list.forEach(student -> System.out.println(student));//输出查询结果
        //关闭sqlSession,还回数据库连接池
        sqlSession.close();
    }
}

为什么要用 List<Student> 来存储查询数据?
因为查询结果是一个student对象,而mybatis会在底层帮我们将查询结果封装为一个对象放进list中。
注意,就算只查询一个字段,如name,返回结果依然是Student对象

如:

在映射文件中加入一条语句

    <!--
        按照id来进行查询
            mybatis中Integer的别名是_int或integer,String的别名为string
    -->
    <select id="getOneById" parameterType="_int" resultType="string">
        select name
        from student
        where id=#{id}
    </select>

测试类:

    @Test
    public void test1() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        String name = sqlSession.selectOne("test.getOneById",1);
        System.out.println(name);
        //关闭sqlSession,还回数据库连接池
        sqlSession.close();
    }

2.Mybatis的增删改查

1.查询

1.查询所有字段

映射文件:

    <select id="getAll" resultType="org.example.pojo.Student">
        select id,name,email,age
        from student
    </select>

测试类:

    @Test
    public void test() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        List<Student> list = sqlSession.selectList("test.getAll");
        list.forEach(student -> System.out.println(student));//输出查询结果
        //关闭sqlSession,还回数据库连接池
        sqlSession.close();
    }

2.查询单个字段

    <select id="getOneById" parameterType="_int" resultType="string">
        select name
        from student
        where id=#{id}
    </select>

测试类:

    @Test
    public void test1() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        String name = sqlSession.selectOne("test.getOneById",1);
        System.out.println(name);
        //关闭sqlSession,还回数据库连接池
        sqlSession.close();
    }

3.模糊查询

映射文件:

    <!--模糊查询
        List<Student> getByName
    -->
    <select id="getByName" parameterType="string" resultType="org.example.pojo.Student">
        select id,name,email,age
        from student
        where name like '%${name}%'
    </select>

测试类:

    @Test
    public void test() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        List<Student> list = sqlSession.selectList("test.getByName","张");
        list.forEach(student -> System.out.println(student));//输出查询结果
        //关闭sqlSession,还回数据库连接池
        sqlSession.close();
    }

2.增加

映射文件:

    <!--增加学生
        int insert(Student stu)
    -->
    <insert id="insert" parameterType="org.example.pojo.Student">
        insert into student (name,email,age)
        values (#{name},#{email},#{age})
    </insert>

测试类:

    @Test
    public void test() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //调用方法
        int num = sqlSession.insert("test.insert",new Student(" 刘一","45951456@126.com",19));
        //********************增删改之后,必须手动提交事务*********************
        sqlSession.commit();
        sqlSession.close();
    }

3.删除

    <!--删除学生
        int delete(Integer id);
    -->
    <delete id="delete" parameterType="int">
        delete from student
        where id=#{id}
    </delete>
    @Test
    public void test2() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //调用方法
        int num = sqlSession.delete("test.delete",5);
        sqlSession.commit();
        sqlSession.close();
    }

4.更改

    <!--更新学生
    int update(Integer id);
    -->
    <update id="update" parameterType="org.example.pojo.Student">
        update student
        set name=#{name},email=#{email},age=#{age}
        where id=#{id}
    </update>
    @Test
    public void test2() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //调用方法
        int num = sqlSession.update("test.update",new Student(4,"赵七","46465@qq.com",20));
        sqlSession.commit();
        sqlSession.close();
    }

3.mybatis数据映射

4.mybatis对象分析

    @Test
    public void test() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        List<Student> list = sqlSession.selectList("test.getAll");
        list.forEach(student -> System.out.println(student));//输出查询结果
        //关闭sqlSession,还回数据库连接池
        sqlSession.close();
    }

Resources类

  • 解析 SqlMapConfig.xml 文件,创建出相应的对象
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");

SqlSessionFactory 接口

  • DefaultSqlSessionFactory 实现类,此类创建出DefaultSqlSession(SqlSession的实现类)

SqlSessionFactoryBuilder类

  • SqlSessionFactory对象(DefaultSqlSessionFactory)由SqlSessionFactoryBuilder的build()创建。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession接口

  • DefaultSqlSession 实现类,此类由DefaultSqlSession创建
  • 这个实现类可以进行增删查改以及事务操作

Executor接口

  • DefaultSqlSession 通过调用Executor执行器来执行sql语句

5.简化之前的测试代码

没有简化前的测试代码:

    @Test
    public void test() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        List<Student> list = sqlSession.selectList("test.getAll");
        list.forEach(student -> System.out.println(student));//输出查询结果
        //关闭sqlSession,还回数据库连接池
        sqlSession.close();
    }

先将固定写法部分封装为一个方法

	//设置为全局变量
    SqlSession sqlSession;

    @Before //在所有@Test方法执行前先执行的方法
    public void openSqlSession() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //创建SqlSession对象
        sqlSession = factory.openSession();
    }

    @After
    public void closeSqlSession(){
        sqlSession.close();
    }	

其他测试方法的写法:

    @Test
    public void test() throws IOException {
        //完成查询操作
        List<Student> list = sqlSession.selectList("test.getAll");
        list.forEach(student -> System.out.println(student));//输出查询结果
    }

6.优化映射文件——为实体类注册别名

未优化前的映射文件的查询语句:

    <select id="getAll" resultType="org.example.pojo.Student">
        /*不使用*查询,因为*查询的效率极低*/
        select id,name,email,age
        from student
    </select>

1.单个实体类别名的注册

在核心配置文件 SqlMapConfig.xml中去注册Student类的别名

    <!--注册实体类的别名-->
    <typeAliases>
        <!--单个实体类别名的注册-->
        <typeAlias type="org.example.pojo.Student" alias="student"></typeAlias>
    </typeAliases>

然后就可以将映射文件中的 org.example.pojo.Student 更改为 student

    <select id="getAll" resultType="student">
        /*不使用*查询,因为*查询的效率极低*/
        select id,name,email,age
        from student
    </select>

2.批量注册

当实体包下面的类有很多的时候(即数据库里面有很多张表),就用批量注册去注册这个包下的实体类的别名。

    <typeAliases>
        <!--批量注册别名
                别名是类名的驼峰命名法(规范)
                org.example.pojo包下的类都会自动根据上述规范取别名
                如:Student的别名就是student
        -->
        <package name="org.example.pojo"/>
    </typeAliases>

7.设置日志输出查看底层执行

    <!--设置日志输出底层执行的代码-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

运行下列测试代码:

    @Test
    public void test3() throws IOException {
        //完成查询操作
        List<Student> list = sqlSession.selectList("test.getAll");
        list.forEach(student -> System.out.println(student));//输出查询结果
    }

查看控制台输出: