Mybatis入门到入坟 一站式基础及进阶——囊括面试点与初学基础、框架分析——从0到1 不会私我 我手把手教你

📖本篇内容:Mybatis入门到入坟一站式基础——囊括面试点与初学基础、框架分析

📆 最近更新:2022年1月11日 MySQL的最全常用SQL语句 —— 一文可以快速熟悉、回忆sql语句

🙊个人简介:一只二本院校在读的大三程序猿,本着注重基础,打卡算法,分享技术作为个人的经验总结性的博文博主,虽然可能有时会犯懒,但是还是会坚持下去的,如果你很喜欢博文的话,建议看下面一行~(疯狂暗示QwQ)

🌇 点赞 👍 收藏 ⭐留言 📝 一键三连 关爱程序猿,从你我做起

本文目录

Mybatis入门到入坟一站式基础

写在前面

哇咔咔,小付又来了哦~今天给大家整理的是关于SSM中Mybatis框架的入门到入坟的基础夯实学习资料, 这次是小付二刷的经历过往,耗时也不算太多,更加坚固了基础知识的掌握的同时,也深刻理解了,Mybatis部分底层源码实现的工作流程,感谢各位支持,但我希望这篇文章能带给你们更多的是知识的查缺补漏,以及对框架的熟练掌握,加油xdm,冲冲冲~!

1、什么是Mybatis

Mybatis介绍

Mybatis介绍

Mybatis是一款优秀的持久化框架:

  • 它支持定制化 SQL、存储过程以及高级映射。
  • MyBatis 避免了几乎所有的JDBC 代码手动设置参数以及获取结果集
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录

ORM是什么?

orm是什么?

ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中。

Mybatis的优缺点

优点:

  • 基于SQL语句进行编程,较为灵活,可以定制化SQL语句
  • 因为SQL写在了xml文件当中,解除了数据持久化与代码程序的耦合性便于管理
  • 相较于JDBC降低了代码冗余的同时,也不用手动关闭连接,从而浪费资源
  • 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护
  • 能够与Spring很好的集成,都属于非侵入式框架。

缺点:

  • SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求,你会体验到写高中作文的感受。
  • SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

Hibernate 和 MyBatis 的区别

共同点:

  • 都对JDBC进行了封装,同时都是持久化层开发的框架,都用于DAO层的开发

不同点:

  • 映射关系
    • MyBatis 是一个半自动映射的框架,配置Java对象与sql语句执行结果的对应关系,多表关联关系配置简单
    • Hibernate 是一个全表映射的框架,配置Java对象与数据库表的对应关系,多表关联关系配置复杂
  • 开发难易程度以及使用场景
    • Hibernate是重量级框架,学习起来较为困难,适合于需求相对稳定的中小型项目,办公等小型系统。
    • Mybatis是轻量级的框架,学习起来较为轻松,适合于需求变化频繁,大型项目,例如电子商务系统。

2、快速入门使用Mybatis

步骤1:搭建Mybatis的环境

步骤1:搭建Mybatis的环境

添加驱动包(mybatis.jar与mysql.jar)

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
    </dependencies>

步骤2:快速创建一个数据库并且包含一张表作为测试

步骤2:快速创建一个数据库并且包含一张表作为测试

CREATE DATABASE `mybatis`;

USE `mybatis`;

CREATE TABLE `user`(
	`id` INT(64) NOT NULL PRIMARY KEY,
	`username` VARCHAR(30) DEFAULT NULL,
	`password` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO user(`id`,`username`,`password`) VALUES(101,'Alascanfu','123456'),
(102,'root','root'),
(103,'admin','admin');

步骤3:创建配置文件 mybatis-config.xml进行配置

步骤3:创建配置文件 mybatis-config.xml进行配置

配置文件需要配置:

  • 指定数据库的相关信息(url,username,password,driver)
  • 框架可以根据配置文件自动获取连接
  • 指定事务管理对象

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="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
        
        <environment id="otherDevelopment">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
<!--    指定mapper文件的路径-->
    <mappers>
        <mapper resource="com.alascanfu.pojo.mapper.UserMapper.xml"/>
    </mappers>

</configuration>

步骤4:创建一个MybatisUtils工具类 获取SqlSession

步骤4:创建一个MybatisUtils工具类 获取SqlSession

/**
 * 功能描述
 * sqlSessionFactory ----> sqlSession
 * Mybatis的工具类 用来获取sqlSession
 * @author Alascanfu
 * @date 2022/1/9
 */
public class MybatisUtils {
    private static InputStream inputStream;
    private static SqlSessionFactory sqlSessionFactory;
    //利用静态代码块直接在初始化时加载
    static {
        try {
            String resource = "mybatis-config.xml";
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 功能描述
     * 获取sqlSession
     * @date 2022/1/9
     * @author Alascanfu
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
    
    /**
     * 功能描述
     * 关闭流与断开SqlSession连接
     * @date 2022/1/9
     * @author Alascanfu
     */
    public static void closeSqlSession(){
        try {
            inputStream.close();
            getSqlSession().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

步骤5:创建实体类与接口类

步骤5:创建实体类与接口类

User.java

public class User {
    private int id ;
    private String username;
    private String password;
    
    public User() {
    }
    
    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Override
    public String toString() {
        return "User{" +
            "id=" + id +
            ", username='" + username + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

接口UserMapper.java

public interface UserMapper {
    List<User> getUserList();
}

编写一个Mapper配置文件,来代替了之前JDBC中的UserDaoImpl的接口实现类

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">
<!--namespace 绑定一个对应的Mapper接口-->
<mapper namespace="com.alascanfu.pojo.mapper.UserMapper">
    <select id="getUserList" resultType="com.alascanfu.pojo.User">
        select * from user
    </select>
</mapper>

步骤6:测试

步骤6:测试

UserMapperTest.java

public class UserMapperTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        List<User> userList =
            mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        
        sqlSession.close();
    }
}

运行结果:

User{id=101, username='Alascanfu', password='123456'}
User{id=102, username='root', password='root'}
User{id=103, username='admin', password='admin'}

Process finished with exit code 0

如果测试类进行测试的时候可能会报错

要先进行配置好maven的过滤环境

否则在测试的时候就会找不到咱们设置好的xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mybatis-01-test</artifactId>
        <groupId>com.alascanfu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-02-HelloMybatis</artifactId>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 配置好过滤Maven配置文件-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

</project>

3、Mybatis实现CRUD操作——以及简单操作

步骤1:需要合理设计好对应了映射类,属性命名最好=列名

步骤1:需要合理设计好对应了映射类,属性命名最好=列名

步骤2:在Mapper接口中,定义对应的方法,增删改的返回值为int(代表的是操作修改的行),而查询则对应返回类型即可。

步骤2:在Mapper接口中,定义对应的方法,增删改的返回值为int(代表的是操作修改的行),而查询则对应返回类型即可。

public interface UserMapper {
    //获取表中的所有User
    List<User> getUserList();
    //插入一个用户
    int insertUser(User user);
    //根据id来删除一个用户
    int deleteUserById(int id);
    //根据id来修改用户
    int updateUserById(User user);
    //查询对应id的用户信息
    User queryUserById(int id);
}

步骤3:当在Mapper接口中,创建好方法后,就要去Mapper的配置文件当中设置对应方法的SQL语句了。

步骤3:当在Mapper接口中,创建好方法后,就要去Mapper的配置文件当中设置对应方法的SQL语句了。

其中mapper中对应的标签名称 也就是翻译过来的 SQL映射语句

insert 插入

delete 删除

update 更新

select 查询

标签内的属性:

  • parameterType:参数的类型
  • resultType:返回值类型
<?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="com.alascanfu.pojo.mapper.UserMapper">

<!-- 增加一个用户 这里的参数类型一定要写对应位置的返回类型 以免出错-->
    <insert id="insertUser" parameterType="com.alascanfu.pojo.User">
        insert into user (id,username,password) values(#{id},#{username},#{password})
    </insert>
<!-- 删除一个用户 -->
    <delete id="deleteUserById" parameterType="int">
        delete from USER where id = #{id}
    </delete>
    
<!-- 根据id更新用户信息 -->    
    <update id="updateUserById" parameterType="com.alascanfu.pojo.User">
        update user set username = #{username},password=#{password} where id = #{id}
    </update>

<!-- 查询所有用户信息 -->
    <select id="getUserList" resultType="com.alascanfu.pojo.User">
        SELECT * FROM USER
    </select>
<!-- 根据用户id查询用户信息 -->    
    <select id="queryUserById" resultType="com.alascanfu.pojo.User">
        select * from user where id = #{id}
    </select>

</mapper>

注意内容:

#{属性值(参数名称)}

步骤4:连接数据库进行测试

步骤4:连接数据库进行测试

public class Test {
    //用于测试查询所有的用户信息
    @org.junit.Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList =
            mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
    //用于测试插入一个用户
    @org.junit.Test
    public void testInsert(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.insertUser(new User(104,"DBA","DBA"));
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
    //用于测试删除一个用户
    @org.junit.Test
    public void testDeleteById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUserById(102);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
    //用于测试更新用户信息
    @org.junit.Test
    public void testUpdateById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int row = mapper.updateUserById(new User(103, "root", "123456"));
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
    //用于测试根据id查询用户信息
    @org.junit.Test
    public void testQueryById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(101);
        System.out.println(user);
    
    }
}

CRUD中的注意事项:

增删改的时候需要提交事务

 session.commit(); 
 session.rollback();    

查询的时候要添加resultType属性

CRUD中多个参数数据的处理

将多个参数封装到map集合当中,再将map集合传递给mapper文件。

获取map中对应的值

#{map的key值}

在Mapper接口中定义方法:

当需要传入多个参数的时候,使用map集合来进行传参

    int insertUsers(Map map);

Mapper配置文件中设置参数为map类型

    <insert id="insertUsers" parameterType="map">
        insert into user (id,username,password) values (#{uId},#{uUsername},#{uPassword});
    </insert>

Test.java

@org.junit.Test
    public void testInsertUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map map = new HashMap();
    //重点在下面这三行
        map.put("uId",105);
        map.put("uUsername","DBA");
        map.put("uPassword","123456");
        mapper.insertUsers(map);
        User user = mapper.queryUserById(105);
        System.out.println(user);
    }

不同线程下的处理优化SqlSession工具类进阶

ThreadLocal是什么?

我认为的ThreadLocal自如其名,就是代表的线程的局部变量,就好比一个线程正在运行当中,ThreadLocal的变量只可以被其自身线程调用、访问,别的线程均无法访问,是避免线程竞争的好东西,他不是解决冲突,而是从根本上避免了冲突的发生。使得线程之间独立运行,并发下安全问题的好帮手。

ThreadLocal的功能

为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

代码测试理解

public class ThreadLocalTest {
    
    public static void main(String[] args) {
        final ThreadLocal<String> threadLocal = new ThreadLocal<String>();
        final List<String> list = new ArrayList<String>();
        new Thread(new Runnable() {
            public void run() {
                System.out.println("A线程开始存入值");
                threadLocal.set("A线程存入的threadLocal变量内容");
                list.add("A线程存入的list内容");
                System.out.println("A====>获取线程的局部变量内容"+ threadLocal.get());
                System.out.println("A====>获取线程的list变量内容"+ list.get(0));
            }
        }).start();
    
        new Thread(new Runnable() {
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("B线程开始取出A线程存入的值");
                System.out.println("B====>获取线程A的局部变量内容"+ threadLocal.get());
                System.out.println("B====>获取线程A存入的list变量内容"+ list.get(0));
            }
        }).start();
    }
}

执行结果:

A线程开始存入值
A====>获取线程的局部变量内容A线程存入的threadLocal变量内容
A====>获取线程的list变量内容A线程存入的list内容
B线程开始取出A线程存入的值
B====>获取线程A的局部变量内容null
B====>获取线程A存入的list变量内容A线程存入的list内容

Process finished with exit code 0

你会发现B线程无法获取A线程设置的局部变量,而可以获得ArrayList中的变量,从侧面也就说明了ArrayList的线程不安全问题。

使用ThreadLocal优化SqlSession

**原理:**在之前已经提到过了SqlSession会在每次用户请求信息时,都会生成一个SqlSession对象实例,在处理数据的过程中也可能会出现多线程的问题。

ThreadLocal的set方法会使用一个map,将当前线程信息作为key,要set的值作为value存储

set()方法的源码:

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

SqlSessionUtils工具类优化

/**
 * 功能描述
 * 通过ThreadLocal来优化的获取SqlSession的工具类
 * @author Alascanfu
 * @date 2022/1/10
 */

public class SqlSessionUtils {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     *功能描述
     * 单例模式下安全的获得SqlSession
     * @date 2022/1/10
     *  @author Alascanfu
     */
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = threadLocal.get();
        if (sqlSession == null){
            sqlSession = sqlSessionFactory.openSession();
            threadLocal.set(sqlSession);
        }
        return sqlSession;
    }
    
    /**
     * 功能描述
     * 关闭连接的工具类
     * @date 2022/1/10
     * @author Alascanfu
     */
    public static void closeSqlSession(){
        SqlSession sqlSession = threadLocal.get();
        if (sqlSession != null){
            sqlSession.close();
            threadLocal.remove();
        }
    }
}

自增主键的操作

用于设置了自增主键的属性上

方便设置

<insert id="insertUserByIncrease" useGeneratedKeys="true" keyProperty="id">

</insert>

测试用例

<insert id="insertUserByIncrease" parameterType="com.alascanfu.pojo.User" useGeneratedKeys="true" keyProperty="id">
        insert into user(username,password) values (#{username},#{password});
    </insert>

Test.java

@org.junit.Test
    public void testInsertUserByIncrese(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = new User();
        user1.setUsername("HHXF");
        user1.setPassword("123");
        int i = mapper.insertUserByIncrease(user1);
        System.out.println(mapper.queryUserById(104));
    }

log4j显示sql的执行语句

首先先导入log4j的jar包

		<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

然后resources文件夹下创建log4j.properties进行配置数据库的日志

log4j.rootLogger=DEBUG, Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

最后去测试 测试结果

2022-01-10 20:30:42,991 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.insertUsers] - ==>  Preparing: insert into user (id,username,password) values (?,?,?);
2022-01-10 20:30:43,017 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.insertUsers] - ==> Parameters: 105(Integer), DBA(String), 123456(String)
2022-01-10 20:30:43,019 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.insertUsers] - <==    Updates: 1
2022-01-10 20:30:43,020 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.queryUserById] - ==>  Preparing: select * from user where id = ?
2022-01-10 20:30:43,020 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.queryUserById] - ==> Parameters: 105(Integer)
2022-01-10 20:30:43,043 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.queryUserById] - <==      Total: 1
User{id=105, username='DBA', password='123456'}

4、Mybatis 进阶 复杂查询操作

1、Mybatis中 如何使用in查询

Mybatis中 如何使用in查询

这里先用MySQL中来演示在SQL服务器中是如何使用in来进行查询的

in 一般用于 where 的表达式当中,其作用是用来查询某个范围之内的数据

示例:

mysql> show tables;
+-------------------+
| Tables_in_mybatis |
+-------------------+
| department        |
| employee          |
| employeeec        |
| employeeremove    |
| employeetrain     |
| empsalary         |
| hr                |
| hr_role           |
| mail_send_log     |
| user              |
+-------------------+
10 rows in set (0.01 sec)

mysql> desc user;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int         | NO   | PRI | NULL    | auto_increment |
| username | varchar(30) | YES  |     | NULL    |                |
| password | varchar(30) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
3 rows in set (0.04 sec)

mysql> select * from user;
+-----+-----------+----------+
| id  | username  | password |
+-----+-----------+----------+
| 101 | Alascanfu | 123456   |
| 102 | root      | root     |
| 103 | admin     | admin    |
| 108 | HHXF      | 123      |
+-----+-----------+----------+
4 rows in set (0.04 sec)

mysql> select * from user where id in (101,108);
+-----+-----------+----------+
| id  | username  | password |
+-----+-----------+----------+
| 101 | Alascanfu | 123456   |
| 108 | HHXF      | 123      |
+-----+-----------+----------+
2 rows in set (0.00 sec)

not in 与之相反

需要注意的是:在in之后依然可以跟函数哦~

咱们言归正传——来说说如何在Java中的配置文件中使用呢?

  • 首先啊,你们需要知道 in 后面跟着的是 foreach 这个标签
  • foreach标签中的属性说明:
    • item 表示迭代过程中的每个元素的别名
    • index 指定的是一个名字,用于表示在迭代过程中,迭代的位置
    • open表示该语句 以什么开始
    • separator 表示在每次进行迭代之间以什么符号作为分隔符
    • close 表示以什么符号结束

步骤1:在Mapper接口中创建对应的查询方法

public interface UserMapper {
    
    List<User> findInList(List list);
    
    List<User> findInArray(int[] arr);
    
    List<User> findInMap(Map map);
}

步骤2:在Mapper的配置文件中书写复杂查询的SQL语句

<?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="com.alascanfu.pojo.mapper.UserMapper">

    <select id="findInList" resultType="com.alascanfu.pojo.User">
        select * from user where id in
        <foreach collection="list" item="uid" open="(" close=")" separator=",">
            #{uid}
        </foreach>
    </select>
    <select id="findInArray" resultType="com.alascanfu.pojo.User">
        select * from user where id in
        <foreach collection="array" open="(" close=")" separator="," item="uid">
            #{uid}
        </foreach>
    </select>
    <select id="findInMap" resultType="com.alascanfu.pojo.User">
        select * from user where id in
        <foreach collection="keyVal" open="(" close=")" separator="," item="uid">
            #{uid}
        </foreach>
    </select>

</mapper>

步骤3:单元测试 是否满足条件

	@org.junit.Test
    public void testInList(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(101);
        list.add(108);
        for (Integer i : list) {
            System.out.println(i);
        }
        List<User> userList = mapper.findInList(list);
        for (User user : userList) {
            System.out.println(user);
        }
    }
	@org.junit.Test
    public void testInArr(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int [] arr = new int[2];
        arr[0] = 101;
        arr[1] = 108;
    
        List<User> userList = mapper.findInArray(arr);
        for (User user : userList) {
            System.out.println(user);
        }
    }
	@org.junit.Test
    public void testInMap(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map map = new HashMap();
        List<Integer> list = new ArrayList<Integer>();
        list.add(101);
        list.add(108);
        map.put("keyVal",list);
        List<User> userList = mapper.findInMap(map);
        for (User user : userList) {
            System.out.println(user);
        }
    }

执行结果:

101
108
2022-01-11 17:38:23,010 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findInList] - ==>  Preparing: select * from user where id in ( ? , ? )
2022-01-11 17:38:23,079 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findInList] - ==> Parameters: 101(Integer), 108(Integer)
2022-01-11 17:38:23,112 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findInList] - <==      Total: 2
User{id=101, username='Alascanfu', password='123456'}
User{id=108, username='HHXF', password='123'}

Process finished with exit code 0

和预期结果一致QwQ

但是需要注意的点在于你传入Map 作为参数的时候 collection 传入的是key值 也就是说明你需要先创建一个集合添加到map当中然后并给这个map赋予key,然后通过collection调用的时候就只能用key来获取。

2、Mybatis中 如何使用模糊查询

使用模糊查询 首先要防止SQL注入问题咱们就需要用到动态的SQL语句

<if test="username!=null and username!=''">
	and username like "%"#{username}"%"
</if>

测试用例:

步骤1:我们需要现在Mapper接口中定义相关的模糊查询方法

public interface UserMapper {
    List<User> findLike(Map map);
}

步骤2:然后我们需要在对应的Mapper的配置文件进行书写SQL语句

    <select id="findLike" resultType="com.alascanfu.pojo.User">
        select * from USER where 1=1
        <if test="username!=null and username!=''">
            and username like "%"#{username}"%"
        </if>
    </select>

<if test="username!=null and username!=''">

这一段代码是为了防止SQL注入导致的恶意查询

步骤3:进行测试

public void testLike(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map map = new HashMap();
        map.put("username","a");
        List<User> userList = mapper.findLike(map);
        for (User user : userList) {
            System.out.println(user);
        }
    }

测试结果:

2022-01-11 18:28:44,935 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findLike] - ==>  Preparing: select * from USER where 1=1 and username like "%"?"%"
2022-01-11 18:28:44,974 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findLike] - ==> Parameters: a(String)
2022-01-11 18:28:45,005 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findLike] - <==      Total: 2
User{id=101, username='Alascanfu', password='123456'}
User{id=103, username='admin', password='admin'}

Process finished with exit code 0

答案如预期的一致~

注意点:

传递的参数如果是map类型的话,则test属性中写的就是key。

同时

#{} 相当于占位符

${} 表示拼接 可能会引起SQL注入问题

test属性中读取属性值时直接写属性名

模糊查询读取属性时使el 表达式, 标签调用的时候

${属性名}

除以上位置外,都使用#{属性名}

3、Mybatis中 如何进行区间查询

步骤1:在Mapper接口中书写对应的接口方法

List<User> findArea(Map map);

步骤2: 在Mapper配置文件中书写SQL语句

	<select id="findArea" resultType="com.alascanfu.pojo.User">
        select * from user where 1=1 and id
        <if test="endId!=null and endId!=''">
            between #{startId} and #{endId}
        </if>
    </select>

步骤3:测试

@org.junit.Test
    public void testBetween(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map map = new HashMap();
        map.put("startId",102);
        map.put("endId",105);
        List<User> userList = mapper.findArea(map);
        for (User user : userList) {
            System.out.println(user);
        }
    }

执行结果

2022-01-11 18:46:53,056 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findArea] - ==>  Preparing: select * from user where 1=1 and id between ? and ?
2022-01-11 18:46:53,102 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findArea] - ==> Parameters: 102(Integer), 105(Integer)
2022-01-11 18:46:53,130 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.findArea] - <==      Total: 2
User{id=102, username='root', password='root'}
User{id=103, username='admin', password='admin'}

5、Mybatis 进阶 多表之间复杂操作 以及 进阶使用

1、处理单个表中的关系

可以通过过resultMap 处理表的关系

为数据库表中的列起别名 = 属性名 同样可以映射数据

步骤1:在Mapper的配置文件中创建一个resultMap的映射关系

    <resultMap id="userResultMap" type="com.alascanfu.pojo.User">
        <id property="id" column="id" jdbcType="INTEGER" javaType="int"/>
        <id property="username" column="username" jdbcType="VARCHAR"/>
        <id property="password" column="password" jdbcType="VARCHAR"/>
    </resultMap>

注意:这里的properties对应的数据是你type中的属性值

而column对应的是数据库中的列头属性

步骤2:在对应的方法中添加返回resultMap类型

	<select id="findArea" resultMap="userResultMap">
        select * from user where 1=1 and id
        <if test="endId!=null and endId!=''">
            between #{startId} and #{endId}
        </if>
    </select>

2、处理多个表之间的关系

两表联合查询:一对一和多对一

注意事项:

单表查询 selet中使用resultType 设置返回的类型即可。但是如果在多表查询,返回的就需要使用自定义的resultMap对查询结果进行映射

一表对多表查询

步骤1:初始化数据库表

create table `role`(
    `id` int not null primary key ,
    `name` varchar(32) default null,
    `nameZh` varchar(256) default null
)engine = innodb default charset = utf8;

create table `user`(
                       `id` int not null primary key ,
                       `username` varchar(32) default null
)engine = innodb default charset = utf8;

create table `user_role`(
                       `id` int not null primary key ,
                       `uid` int default null ,
                       `rid` int default null
)engine = innodb default charset = utf8;

步骤2:向表中插入数据

mysql> select * from user;
+----+-----------+
| id | username  |
+----+-----------+
|  1 | Alascanfu |
|  2 | HHXF      |
+----+-----------+
2 rows in set (0.00 sec)

mysql> select * from role;
+----+-------+--------------------+
| id | name  | nameZh             |
+----+-------+--------------------+
|  1 | admin | 系统管理员         |
|  2 | DBA   | 数据库管理员       |
|  3 | user  | 普通用户           |
+----+-------+--------------------+
3 rows in set (0.00 sec)

mysql> select * from user_role;
+----+-----+-----+
| id | uid | rid |
+----+-----+-----+
|  1 |   1 |   3 |
|  2 |   1 |   1 |
|  3 |   2 |   1 |
|  4 |   2 |   2 |
+----+-----+-----+
4 rows in set (0.00 sec)

初始化类与Mapper接口以及Mapper的配置文件 进行一对多连表查询

Role.java

public class Role {
    private int id ;
    private String name;
    private String nameZh;
    
    public Role() {
    }
    
    public Role(int id, String name, String nameZh) {
        this.id = id;
        this.name = name;
        this.nameZh = nameZh;
    }
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getNameZh() {
        return nameZh;
    }
    
    public void setNameZh(String nameZh) {
        this.nameZh = nameZh;
    }
    
    @Override
    public String toString() {
        return "Role{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", nameZh='" + nameZh + '\'' +
            '}';
    }
}

User.java

public class User1 {
    private int id ;
    private String username;
    private List<Role> roleList;
    
    public User1() {
    }
    
    public User1(int id, String username, List<Role> roleList) {
        this.id = id;
        this.username = username;
        this.roleList = roleList;
    }
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public List<Role> getRoleList() {
        return roleList;
    }
    
    public void setRoleList(List<Role> roleList) {
        this.roleList = roleList;
    }
    
    @Override
    public String toString() {
        return "User{" +
            "id=" + id +
            ", username='" + username + '\'' +
            ", roleList=" + roleList +
            '}';
    }
}

UserMapper.java

public interface UserMapper1 {
    List<User1> getUserById(int 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="com.alascanfu.pojo.mapper.UserMapper1">
    <resultMap id="userList" type="com.alascanfu.pojo.User1">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <collection property="roleList" ofType="com.alascanfu.pojo.Role" >
            <result property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="nameZh" column="nameZh"/>
        </collection>
    </resultMap>

    <select id="getUserById" resultMap="userList">
        select u.id ,u.username,r.name ,r.nameZh from user u,role r,user_role ur where u.id = #{id} and  ur.uid = u.id and ur.rid = r.id
    </select>
</mapper>

Test.java

@org.junit.Test
    public void test(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        List<User1> userList = mapper.getUserById(1);
        for (User1 user1 : userList) {
            System.out.println(user1);
        }
    }

执行结果

User{id=1, username='Alascanfu', roleList=[Role{id=1, name='user', nameZh='普通用户'}, Role{id=1, name='admin', nameZh='系统管理员'}]}

Process finished with exit code 0

上述案例也可以转化为多对多进行多个表关系查询

3、数据库中的分页查询

1、Mybatis自带的接口方法

Mybatis插件接口RowBounds实现对象数据分页

实现步骤:

selectList这个函数的参数为Mapper接口中的方法,第二个是方法中的参数,第三个是偏移量

	@Test
    public void test1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<User> userList = sqlSession.selectList("com.alascanfu.pojo.mapper.UserMapper.getUserList", null, new RowBounds(0, 1));
        for (User user : userList) {
            System.out.println(user);
        }
    }

配置文件

	<select id="getUserList" resultType="com.alascanfu.pojo.User">
        select * from user
    </select>
2、通过插件来实现分页操作

通过使用分页插件来进行分页操作 (一般项目中都采用的这种哦~)

基本原理:

是插件通过使用Mybatis的插件接口,实现自定义的插件。

步骤1:导入分页插件的jar包

  • pagehelper.jar
  • jsqlparser.jar
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.github.jsqlparser/jsqlparser -->
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>4.3</version>
        </dependency>

步骤2:进入Mybatis-config配置文件中添加插件

<?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>
    <properties>
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="fujiawei2013"/>
    </properties>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/alascanfu/pojo/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

步骤3:在查询数据之前配置好分页参数

Page.Helper.startPage(当前页,每页数据条数)

一般要用的时候都是直接复制上去了~

	@org.junit.Test
    public void testForSplitPage(){
        SqlSession sqlSession = SqlSesionUtils.getSqlSession();
    
        PageHelper.startPage(2,2);
    
        List<User> userList = sqlSession.selectList("com.alascanfu.pojo.mapper.UserMapper.getUserList");
    	
        //获取分页之后的分页信息
        PageInfo<User> userPageInfo = new PageInfo<User>(userList);
        for (User user : userPageInfo.getList()) {
            System.out.println(user);
        }
    
        System.out.println("总条数:"+userPageInfo.getTotal());
        System.out.println("当前页面条数:"+userPageInfo.getSize());
        System.out.println("总页数:"+userPageInfo.getPages());
        System.out.println("上一页:"+userPageInfo.getPrePage());
        System.out.println("下一页:"+userPageInfo.getNextPage());
        System.out.println("当前页:"+userPageInfo.getPageNum());
        System.out.println("显示条数:"+userPageInfo.getPageSize());
    
        SqlSesionUtils.closeSqlSession();
    }

运行结果

User{id=1, username='Alascanfu', roleList=[Role{id=1, name='DBA', nameZh='数据库管理员'}]}
User{id=2, username='HHXF', roleList=[Role{id=2, name='DBA', nameZh='数据库管理员'}]}
总条数:24
当前页面条数:2
总页数:12
上一页:1
下一页:3
当前页:2
显示条数:2

4、Mybatis 缓存使用

Mybatis中的缓存分为一级缓存二级缓存:

一级缓存

Mybatis自动开启,无需用户操作设置,而且操作者无法进行关闭可以清除缓存

会在第二次进行查询的时候直接从缓存中拿到

示例测试:

    @org.junit.Test
    public void testForSelectByCache(){
        SqlSession sqlSession = SqlSesionUtils.getSqlSession();
        System.out.println(new Date().toString());
        List<User> userList = sqlSession.selectList("com.alascanfu.pojo.mapper.UserMapper.getUserList");
        System.out.println(new Date().toString());
        System.out.println("=====一级缓存分割线=====");
        userList = sqlSession.selectList("com.alascanfu.pojo.mapper.UserMapper.getUserList");
        System.out.println(new Date().toString());
    
    }

运行结果:

Wed Jan 12 18:14:30 CST 2022
2022-01-12 18:14:32,011 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserList] - ==>  Preparing: select * from user ,role,user_role
2022-01-12 18:14:32,050 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserList] - ==> Parameters: 
2022-01-12 18:14:32,084 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserList] - <==      Total: 24
Wed Jan 12 18:14:32 CST 2022
=====一级缓存分割线=====
Wed Jan 12 18:14:32 CST 2022

说明了当第二次调用SqlSession去查询之前已经查询过得数据已经被添加到缓存当中了,不会再消耗时间进行查询,大大提高了效率。

二级缓存

二级缓存目的是为了允许在不同的缓存中都可以共享数据

步骤1:开启缓存的使用 mybatis-config.xml中

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

步骤2:在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="com.alascanfu.pojo.mapper.UserMapper">
    <cache eviction="LRU"
            flushInterval="60000"
            size="512"
            readOnly="true"
    />
</mapper>

注意:

  • eviction: 二级缓存中,缓存的对象从缓存中移除的策略,回收策略为最近最久未使用LRU算法

如果不会 手撕 看看下方

手撕LRU缓存数据结构设计 校招高频的面试题 有多高频不用我多说 你也知道 手写——从0到1 看不懂 来找我

请点击这里~

  • flushInterval: 刷新缓存的事件间隔,单位:毫秒
  • size: 缓存对象的个数
  • readOnly: 是否是只读的

代码测试

public class ThreadTestCache {
    @Test
    public void test() throws IOException {
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        new Thread(()->{
            SqlSession sqlSession1 = sqlSessionFactory.openSession();
            System.out.println(Thread.currentThread().getName()+"开始查询."+new Date().toString());
            List<User> userList = sqlSession1.selectList("com.alascanfu.pojo.mapper.UserMapper.getUserList");
            System.out.println(Thread.currentThread().getName()+"结束查询."+new Date().toString());
            sqlSession1.close();
        },"A").start();
    
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            SqlSession sqlSession2 = sqlSessionFactory.openSession();
            System.out.println(Thread.currentThread().getName()+"开始查询."+new Date().toString());
            List<User> userList = sqlSession2.selectList("com.alascanfu.pojo.mapper.UserMapper.getUserList");
            System.out.println(Thread.currentThread().getName()+"结束查询."+new Date().toString());
        },"B").start();
    }
}

执行结果:

A开始查询.Wed Jan 12 19:02:33 CST 2022
2022-01-12 19:02:33,996 [A] DEBUG [com.alascanfu.pojo.mapper.UserMapper] - Cache Hit Ratio [com.alascanfu.pojo.mapper.UserMapper]: 0.0
2022-01-12 19:02:35,185 [A] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserList] - ==>  Preparing: select * from user ,role,user_role
2022-01-12 19:02:35,222 [A] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserList] - ==> Parameters: 
2022-01-12 19:02:35,256 [A] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserList] - <==      Total: 24
A结束查询.Wed Jan 12 19:02:35 CST 2022
B开始查询.Wed Jan 12 19:02:35 CST 2022
2022-01-12 19:02:35,986 [B] DEBUG [com.alascanfu.pojo.mapper.UserMapper] - Cache Hit Ratio [com.alascanfu.pojo.mapper.UserMapper]: 0.5
B结束查询.Wed Jan 12 19:02:35 CST 2022

Cache Hit Ratio [com.alascanfu.pojo.mapper.UserMapper]: 0.5

代表命中率为0.5

6、Mybatis的配置文件以及配置优化

mybatis-config配置文件详解

配置的时候要注意mybatis-config.xml文件中的configuration标签里面的子标签必须遵循以下顺序排序,否则会报错

1.properties
2.settings
3.typeAliases
4.typeHandlers
5.objectFactory
6.objectWrapperFactory
7.reflectorFactory
8.plugins
9.environments
10.databaseldProvider
11.mappers

1、环境配置 environments

当在环境配置中配置了多个环境,但是每个SqlSessionFactory实例只能选择其中的一个环境

	<environments default="testDevelopment">
        <environment id="testDevelopment">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url1}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>

        <environment id="myBatisDevelopment">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url2}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

enviroments中配置:

  • enviroment 标签中的id属性则是称之为当前环境标识enviroments可以通过修改 default 属性来默认选择数据库环境。
    • enviroment下的transactionManager标签控制了事务管理的配置
    • 数据源中配置 type属性

transactionManager中配置

  • type属性只有两个值:JDBC与MANAGED
  • JDBC 直接使用了JDBC的提交和回滚等设置
  • 而MANAGED是由人员关注整个生命周期作用域,而且默认会关闭连接。

dataSource中配置

  • type属性有三个值:【UNPOOLED|POOLED|JNDI】
  • UNPOOLED:数据源的实现是会在每次被请求时打开和关闭连接
    • 常用的属性:
      • driver
      • url
      • username
      • password
      • defaultTransactionIsolation ——默认的连接事务隔离级别
  • POOLED:池化技术、避免创建数据库初始化和认证的时间、节约资源
2、属性配置properties

可以通过properties属性实现引用配置文件的同时也可以在mybatis中配置这个标签,然后配置其他数据时通过 ${属性名}来进行调用。

	<properties>
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url1" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
        <property name="url2" value="jdbc:mysql://localhost:3306/test1?characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
    </plugins>

    <environments default="testDevelopment">
        <environment id="testDevelopment">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url1}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>

        <environment id="myBatisDevelopment">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url2}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

引入外部的properties文件

<properties resource="db.properties"/>
3、类型别名配置 typeAliases

这个标签的作用主要是为了Java类型设置一个较短的名字,它只是和XML配置有关。

防止在Mapper配置文件中冗余

	<typeAliases>
        <typeAlias type="com.alascanfu.pojo.User" alias="User"/>
    </typeAliases>

可以给Java中的实体类取别名,大大降低了代码冗余的情况,进行优化

也可通过配置其扫描指定包名,Mybatis会在相应的包名下面搜索需要的Java Bean

UserMapper.xml

	<resultMap id="userAndRole" type="User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <collection property="roleList" ofType="Role">
            <result property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="nameZh" column="nameZh"/>
        </collection>
    </resultMap>

mybatis-config.xml

<typeAliases>
        <package name="com.alascanfu.pojo"/>
    </typeAliases> 

第一种适合实体类较少的时候使用,第二种方式适合实体类多的时候使用

同时第一种可以自定义别名,第二种需要通过注解@Alias(“别名”)来进行使用

4、设置配置 setting
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
5、映射器 Mapper

resource

资源映射器

<mappers>
    <mapper resource="com/alascanfu/pojo/mapper/UserMapper.xml"/>
</mappers>

package

包内资源映射器

<mappers>
    <package name="com.alascanfu.pojo.mapper"/>
</mappers>

7、Mybatis工作原理及其进阶

Mybatis的编程流程

Mybatis的编程步骤是如何进行的?

步骤1:通过SqlSessionFactoryBuilder这个建造者模式通过配置文件静态创建SqlSessionFactorySqlSessionFactory一经被创建就应该在应用的运行期间一直存在,单例模式,而此时获得的到了SqlSessionFactory之后就不再需要SqlSessionFactoryBuilder了。

步骤2:通过创建得到的SqlSessionFactory来获取得到SqlSession。这里需要了解一下SqlSession的实例并不是线程安全的,所以被能被共享,同时它的最佳作用域是请求或者方法作用域当中。

步骤3:通过SqlSession来执行数据库的操作,需要注意的是:每当收到HTTP请求,就可以打开一个SqlSession,返回一个响应之后,才会关闭它

步骤4:通过调用sqlSession.commit()方法提交事务。

步骤5:关闭会话连接,关闭流的使用,释放资源。

8、Mybatis中日志进阶使用

1、 日志工厂

日志是为了让我们在数据库操作过程中,我们需要进行排错,日志就是最好的拍错工具。

设置在Setting当中的 logImpl 指定MyBatis所用日志的具体实现。

  • SLF4J
  • LOG4J
  • LOG4J2
  • STDOUT_LOGGING
1、标准控制台输出 STDOUT_LOGGING

Mybatis自带的控制台输出日志

步骤1:通过配置配置文件中的setting来进行

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

步骤2:进行测试

测试结果

Created connection 285133380.
Returned connection 285133380 to pool.
Cache Hit Ratio [SQL_CACHE]: 0.0
Opening JDBC Connection
Checked out connection 285133380 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@10feca44]
==>  Preparing: SELECT count(0) FROM user, role, user_role
==> Parameters: 
<==    Columns: count(0)
<==        Row: 24
<==      Total: 1
==>  Preparing: select * from user ,role,user_role LIMIT ?, ?
==> Parameters: 2(Long), 2(Integer)
<==    Columns: id, username, id, name, nameZh, id, uid, rid
<==        Row: 1, Alascanfu, 2, DBA, 数据库管理员, 1, 1, 3
<==        Row: 2, HHXF, 2, DBA, 数据库管理员, 1, 1, 3
<==      Total: 2
User{id=1, username='Alascanfu', roleList=[Role{id=1, name='DBA', nameZh='数据库管理员'}]}
User{id=2, username='HHXF', roleList=[Role{id=2, name='DBA', nameZh='数据库管理员'}]}
总条数:24
当前页面条数:2
总页数:12
上一页:1
下一页:3
当前页:2
显示条数:2
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@10feca44]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@10feca44]
Returned connection 285133380 to pool.

工作原理:

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.

在控制台一开始输出的就是StdOutImpl这个适配器类就已经被初始化用来进行日志输出。

StdOutImpl.java 源码

/**
 * @author Clinton Begin
 */
public class StdOutImpl implements Log {

  public StdOutImpl(String clazz) {
    // Do Nothing
  }

  @Override
  public boolean isDebugEnabled() {
    return true;
  }

  @Override
  public boolean isTraceEnabled() {
    return true;
  }

  @Override
  public void error(String s, Throwable e) {
    System.err.println(s);
    e.printStackTrace(System.err);
  }

  @Override
  public void error(String s) {
    System.err.println(s);
  }

  @Override
  public void debug(String s) {
    System.out.println(s);
  }

  @Override
  public void trace(String s) {
    System.out.println(s);
  }

  @Override
  public void warn(String s) {
    System.out.println(s);
  }
}
2、LOG4J输出日志

LOG4J是Apache为Java提供的日志管理工具。他与System.out.println()的作用相似,用来跟踪、调试、维护程序。

前不久阿里某猿发现的惊天漏洞就是关于这个东东的QwQ

快速使用

步骤1:导入与log4j相关的包

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

步骤2:配置log4j的配置文件

log4j.rootLogger=DEBUG, Console ,file
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n


#日志输出级别
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

步骤3:在mybatis-config配置文件中进行配置

<settings>
    <setting name="logImpl" value="LOG4J"/>
</settings>

步骤4:测试使用

	@org.junit.Test
    public void testForSelectById(){
        SqlSession sqlSession = SqlSesionUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> user = mapper.getUserById(1);
        for (User user1 : user) {
            System.out.println(user1);
        }
    }

测试结果

2022-01-12 16:54:03,475 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserById] - ==>  Preparing: select u.id ,u.username,r.id,r.name,r.nameZh from user u ,role r ,user_role ur where u.id = ? and u.id = ur.uid and ur.rid = r.id
2022-01-12 16:54:03,514 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserById] - ==> Parameters: 1(Integer)
2022-01-12 16:54:03,541 [main] DEBUG [com.alascanfu.pojo.mapper.UserMapper.getUserById] - <==      Total: 2
User{id=1, username='Alascanfu', roleList=[Role{id=1, name='user', nameZh='普通用户'}, Role{id=1, name='admin', nameZh='系统管理员'}]}

原理基于的使用:

在对应需要出现测试的地方添加方法 进行日志输出

logger.info()信息提示

logger.debug()debug查错日志

logger.error()报错提示

public class Test {
    
    static Logger logger = Logger.getLogger(Test.class);
    
    @org.junit.Test
    public void testLog4j(){
        logger.info("info:运行log4j");
        logger.debug("debug:运行了log4j");
        logger.error("error:运行了log4j");
    }

}

输出结果:

2022-01-12 17:09:54,739 [main] INFO  [com.alascanfu.Test] - info:运行log4j
2022-01-12 17:09:54,740 [main] DEBUG [com.alascanfu.Test] - debug:运行了log4j
2022-01-12 17:09:54,740 [main] ERROR [com.alascanfu.Test] - error:运行了log4j

文件输出:

[INFO][22-01-12][com.alascanfu.Test]info:运行log4j
[DEBUG][22-01-12][com.alascanfu.Test]debug:运行了log4j
[ERROR][22-01-12][com.alascanfu.Test]error:运行了log4j

9、基于注解开发

这个嘛 因为实际开发基本没咋用过注解 来进行开发

感觉应该不是很重要 这里 后续更新了 会贴链接地哦~

写在最后

哇咔咔~终于完结SSM框架中的Mybatis框架了

这是小付的二刷框架的心得笔记 与 学习经历

本文全文 40091

请放心食用

从开始整理复习到现在三天左右的时间

就快速过了这个在项目中宛如写小作文的框架啦

多注重于实践操作 绝对没有坏处

加油嗷~ 兄弟们

最后

每天进步点 每天收获点

愿诸君 事业有成 学有所获

如果觉得不错 别忘啦一键三连哦~

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alascanfu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值