📖本篇内容: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
这个建造者模式
通过配置文件静态创建SqlSessionFactory
。SqlSessionFactory
一经被创建就应该在应用的运行期间一直存在,单例模式
,而此时获得的到了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
字
请放心食用
从开始整理复习到现在三天左右的时间
就快速过了这个在项目中宛如写小作文的框架啦
多注重于实践操作 绝对没有坏处
加油嗷~ 兄弟们
最后
每天进步点 每天收获点
愿诸君 事业有成 学有所获
如果觉得不错 别忘啦一键三连哦~