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

阅读: 评论:0

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

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

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

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

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

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

本文目录

  • Mybatis入门到入坟一站式基础
    • 写在前面
    • 1、什么是Mybatis
      • Mybatis介绍
      • ORM是什么?
      • Mybatis的优缺点
      • Hibernate 和 MyBatis 的区别
    • 2、快速入门使用Mybatis
      • 步骤1:搭建Mybatis的环境
      • 步骤2:快速创建一个数据库并且包含一张表作为测试
      • 步骤3:创建配置文件 l进行配置
      • 步骤4:创建一个MybatisUtils工具类 获取SqlSession
      • 步骤5:创建实体类与接口类
      • 步骤6:测试
    • 3、Mybatis实现CRUD操作——以及简单操作
      • 步骤1:需要合理设计好对应了映射类,属性命名最好=列名
      • 步骤2:在Mapper接口中,定义对应的方法,增删改的返回值为int(代表的是操作修改的行),而查询则对应返回类型即可。
      • 步骤3:当在Mapper接口中,创建好方法后,就要去Mapper的配置文件当中设置对应方法的SQL语句了。
      • 步骤4:连接数据库进行测试
      • CRUD中的注意事项:
      • CRUD中多个参数数据的处理
      • 不同线程下的处理优化SqlSession工具类进阶
      • 自增主键的操作
      • log4j显示sql的执行语句
    • 4、Mybatis 进阶 复杂查询操作
      • 1、Mybatis中 如何使用in查询
      • 2、Mybatis中 如何使用模糊查询
      • 3、Mybatis中 如何进行区间查询
    • 5、Mybatis 进阶 多表之间复杂操作 以及 进阶使用
      • 1、处理单个表中的关系
      • 2、处理多个表之间的关系
      • 3、数据库中的分页查询
        • 1、Mybatis自带的接口方法
        • 2、通过插件来实现分页操作
      • 4、Mybatis 缓存使用
    • 6、Mybatis的配置文件以及配置优化
        • 1、环境配置 environments
        • 2、属性配置properties
        • 3、类型别名配置 typeAliases
        • 4、设置配置 setting
        • 5、映射器 Mapper
    • 7、Mybatis工作原理及其进阶
      • Mybatis的编程流程
    • 8、Mybatis中日志进阶使用
      • 1、 日志工厂
        • 1、标准控制台输出 STDOUT_LOGGING
        • 2、LOG4J输出日志
    • 9、基于注解开发
    • 写在最后

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&batis</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:创建配置文件 l进行配置

步骤3:创建配置文件 l进行配置

配置文件需要配置:

  • 指定数据库的相关信息(url,username,password,driver)
  • 框架可以根据配置文件自动获取连接
  • 指定事务管理对象
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis//DTD Config 3.0//EN"".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.l"/></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 = &#l";inputStream = ResourceAsStream(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;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + ''' +", password='" + password + ''' +'}';}
}

接口UserMapper.java

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

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

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".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 {@Testpublic void test(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(UserMapper.class);List<User> userList &#UserList();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=".0.0"xmlns:xsi=""xsi:schemaLocation=".0.0 .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 {//获取表中的所有UserList<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 mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".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.Testpublic void test(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(UserMapper.class);List<User> userList &#UserList();for (User user : userList) {System.out.println(user);}}//用于测试插入一个用户@org.junit.Testpublic void testInsert(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(UserMapper.class);mapper.insertUser(new User(104,"DBA","DBA"));List<User> userList = UserList();for (User user : userList) {System.out.println(user);}}//用于测试删除一个用户@org.junit.Testpublic void testDeleteById(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(UserMapper.class);mapper.deleteUserById(102);List<User> userList = UserList();for (User user : userList) {System.out.println(user);}}//用于测试更新用户信息@org.junit.Testpublic void testUpdateById(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(UserMapper.class);int row = mapper.updateUserById(new User(103, "root", "123456"));List<User> userList = UserList();for (User user : userList) {System.out.println(user);}}//用于测试根据id查询用户信息@org.junit.Testpublic void testQueryById(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(UserMapper.class);User user = mapper.queryUserById(101);System.out.println(user);}
}

CRUD中的注意事项:

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

 sessionmit(); llback();    

查询的时候要添加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.Testpublic void testInsertUser(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(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====>获取线程的局部变量内容"+ ());System.out.println("A====>获取线程的list变量内容"+ (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的局部变量内容"+ ());System.out.println("B====>获取线程A存入的list变量内容"+ (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);elsecreateMap(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 = ResourceAsStream(&#l");sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}/***功能描述* 单例模式下安全的获得SqlSession* @date 2022/1/10*  @author Alascanfu*/public static SqlSession getSqlSession(){SqlSession sqlSession = ();if (sqlSession == null){sqlSession = sqlSessionFactory.openSession();threadLocal.set(sqlSession);}return sqlSession;}/*** 功能描述* 关闭连接的工具类* @date 2022/1/10* @author Alascanfu*/public static void closeSqlSession(){SqlSession sqlSession = ();if (sqlSession != null){sqlSession.close();ve();}}
}

自增主键的操作

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

方便设置

<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.Testpublic void testInsertUserByIncrese(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(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进行配置数据库的日志

Logger=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%nlog4j.logger.java.sql.ResultSet=INFO
log4j.logger.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 mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".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.Testpublic void testInList(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(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.Testpublic void testInArr(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(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.Testpublic void testInMap(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(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 = SqlSession();UserMapper mapper = Mapper(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.Testpublic void testBetween(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(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;}@Overridepublic 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 = leList = 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) {leList = roleList;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + ''' +", roleList=" + roleList +'}';}
}

UserMapper.java

public interface UserMapper1 {List<User1> getUserById(int id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".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.Testpublic void test(){SqlSession sqlSession = SqlSession();UserMapper1 mapper = Mapper(UserMapper1.class);List<User1> userList = UserById(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接口中的方法,第二个是方法中的参数,第三个是偏移量

	@Testpublic void test1(){SqlSession sqlSession = SqlSession();List<User> userList = sqlSession.selectList("com.alascanfu.pojo.UserList", 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
<!-- .github.pagehelper/pagehelper --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.1</version></dependency><!-- .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 configurationPUBLIC "-//mybatis//DTD Config 3.0//EN"".dtd"><configuration><properties><property name="driver" value=&#sql.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/l"/></mappers>
</configuration>

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

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

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

	@org.junit.Testpublic void testForSplitPage(){SqlSession sqlSession = SqlSession();PageHelper.startPage(2,2);List<User> userList = sqlSession.selectList("com.alascanfu.pojo.UserList");//获取分页之后的分页信息PageInfo<User> userPageInfo = new PageInfo<User>(userList);for (User user : List()) {System.out.println(user);}System.out.println("总条数:"&#Total());System.out.println("当前页面条数:"&#Size());System.out.println("总页数:"&#Pages());System.out.println("上一页:"&#PrePage());System.out.println("下一页:"&#NextPage());System.out.println("当前页:"&#PageNum());System.out.println("显示条数:"&#PageSize());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.Testpublic void testForSelectByCache(){SqlSession sqlSession = SqlSession();System.out.println(new Date().toString());List<User> userList = sqlSession.selectList("com.alascanfu.pojo.UserList");System.out.println(new Date().toString());System.out.println("=====一级缓存分割线=====");userList = sqlSession.selectList("com.alascanfu.pojo.UserList");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.UserList] - ==>  Preparing: select * from user ,role,user_role
2022-01-12 18:14:32,050 [main] DEBUG [com.alascanfu.pojo.UserList] - ==> Parameters: 
2022-01-12 18:14:32,084 [main] DEBUG [com.alascanfu.pojo.UserList] - <==      Total: 24
Wed Jan 12 18:14:32 CST 2022
=====一级缓存分割线=====
Wed Jan 12 18:14:32 CST 2022

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

二级缓存

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

步骤1:开启缓存的使用 l中

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

步骤2:在Mapper映射的配置文件中进行二级缓存配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".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 {@Testpublic void test() throws IOException {SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().ResourceAsStream(&#l"));new Thread(()->{SqlSession sqlSession1 = sqlSessionFactory.openSession();System.out.println(Thread.currentThread().getName()+"开始查询."+new Date().toString());List<User> userList = sqlSession1.selectList("com.alascanfu.pojo.UserList");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.UserList");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.UserList] - ==>  Preparing: select * from user ,role,user_role
2022-01-12 19:02:35,222 [A] DEBUG [com.alascanfu.pojo.UserList] - ==> Parameters: 
2022-01-12 19:02:35,256 [A] DEBUG [com.alascanfu.pojo.UserList] - <==      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配置文件详解

配置的时候要注意l文件中的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=&#sql.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

	<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>
<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/l"/>
</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:通过调用sqlSessionmit()方法提交事务。

步骤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 [sql.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 [sql.cj.jdbc.ConnectionImpl@10feca44]
Closing JDBC Connection [sql.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}@Overridepublic boolean isDebugEnabled() {return true;}@Overridepublic boolean isTraceEnabled() {return true;}@Overridepublic void error(String s, Throwable e) {println(s);e.);}@Overridepublic void error(String s) {println(s);}@Overridepublic void debug(String s) {System.out.println(s);}@Overridepublic void trace(String s) {System.out.println(s);}@Overridepublic 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的配置文件

Logger=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.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.Testpublic void testForSelectById(){SqlSession sqlSession = SqlSession();UserMapper mapper = Mapper(UserMapper.class);List<User> user = UserById(1);for (User user1 : user) {System.out.println(user1);}}

测试结果

2022-01-12 16:54:03,475 [main] DEBUG [com.alascanfu.pojo.UserById] - ==>  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.UserById] - ==> Parameters: 1(Integer)
2022-01-12 16:54:03,541 [main] DEBUG [com.alascanfu.pojo.UserById] - <==      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查错日志

<()报错提示

public class Test {static Logger logger = Logger(Test.class);@org.junit.Testpublic void testLog4j(){logger.info("info:运行log4j");logger.debug("debug:运行了log4j");("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

请放心食用

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

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

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

加油嗷~ 兄弟们

最后

每天进步点 每天收获点

愿诸君 事业有成 学有所获

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

本文发布于:2024-02-01 22:08:10,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170679648939729.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23