关于Mybatis的学习
思路:搭建环境--》导入Mybatis--》 编写代码--》测试
2.1、搭建环境
搭建数据库:


新建项目
-
新建一个普通的maven项目
-
删除src目录
-
导入maven依赖
<!-- 导入依赖-->
<dependencies>
<!-- mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
2.2、创建一个模块
-
编写mybatis的核心文件(链接数据库)
-
编写mybatis工具类
package com.chen.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
//工具类 sqlSessionFactory --> sqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
static {
try {
//使用mybatis第一步,获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
// 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
public static SqlSession getSqlSession(){
//获得SqlSession
return sqlSessionFactory.openSession();
}
}
2.3、编写代码
-
实体类
package com.chen.pojo;
//实体类
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
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 getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
-
Dao接口
public interface UserDao {
List<User> getUserList();
}
-
接口实现类由原来的UserDaompl转换为Mapper配置文件
2.4、测试
注意点:org.apache.ibatis.binding.BindingException: Type interface com.chen.dao.UserDao is not known to the MapperRegistry.
MapperRegistry是什么?
就是在核心配置文件中注册mappers
-
junit测试
package com.chen.dao;
import com.chen.pojo.User;
import com.chen.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
测试中可能遇到的问题
-
配置文件没有注册
-
绑定接口错误
-
方法名不对
-
返回类型不对
-
Maven导出资源问题
-
一共七步

-
报错The error may exist in com/chen/dao/user-mapper.xml
在pom中配置
<!-- 在build中配置resources来防止我们资源导出失败的问题-->
<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>
3、CRUD
1、namespace
namespace中的包名要和Dao/mapper接口的包名一致!
2、select
查询语句:
-
id:就是对应namespace中的方法名
-
resultType:sql执行的返回值!
-
parameterType:参数类型!
-
编写接口
//查询全部用户
List<User> getUserList();
-
编写对应mapper中对应语句
<select id="getUserList" resultType="com.chen.pojo.User">
<!-- 执行SQL-->
select * from mybatis.user
</select>
-
测试
3、insert
4、update
5、delete
7、万能Map

Map传递参数,直接在sql中取出key即可!
对象传递参数,直接在sql中取对象的属性即可!
只有一个基本类型参数的情况下,可以直接在sql中取到!
多个参数用Map,或者注解!
8、思考题
模糊查询怎么写、
最好在 sql拼接中 将其写死,以防用户传一些花里胡哨的,

在Java代码执行的时候,传递通配符

4、配置解析
1、核心配置文件

2、环境配置

如果有多套环境需要切换,直接在配置文件中将default改为需要的id名即可
学会使用配置多套运行环境
Mybatis默认事务管理器是JDBC,连接池:POOLED
3、属性(properties)
我们可以通过properties属性来实现引用配置文件
这些属性都是可外部配置且可动态替换的,既可在典型的Java属性文件中配置,亦可以通过properties元素的子元素来传递。【db.properties】
编写一个配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT
username=root
password=123456
在核心配置文件中映入
<properties resource="db.properties">
</properties>
<!--一套环境-->
<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>
从外部引入时url可能会报错No suitable driver found for jdbc,这时只需要把映入的url名改为urll或其他即可
也可以直接在核心配置文件中写
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
如果两种都写相同的优先使用外部配置文件
4、类型别名
<typeAliases>
<typeAlias type="com.chen.pojo.User" alias="User"/>
</typeAliases>
扫描实体类的包,他的默认别名就是这个类的类名,首字母小写
<typeAliases>
<package name="com.chen.pojo"/>
</typeAliases>
在实体类较少的时候可以用第一种,较多用第二种,
如果第二种非要改名则需要在实体类上增加注解

5、设置

6、映射器(mapper)
MapperRegistry:注册绑定我们的Mapper文件
方式一:
<mappers>
<mapper resource="com/chen/dao/UserMapper.xml"></mapper>
</mappers>
方式二:使用class方式绑定
<mappers>
<mapper class="com.chen.dao.UserMapper"></mapper>
</mappers>
注意点:
-
接口和他的Mapper配置文件必须同名
-
接口和他的Mapper配置文件必须在同一个包下
方式三:
<mappers>
<package name="com.chen.dao"/>
</mappers>
注意点:
-
接口和他的Mapper配置文件必须同名
-
接口和他的Mapper配置文件必须在同一个包下
5、解决属性名和字段名不一致
1、当属性名和字段名不一致查出的结果

-
第一种方法:直接在sql语句中取与属性名相同的别名

2、resultMap
结果集映射
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.chen.dao.UserMapper">
<!-- 查询语句-->
<!-- 结果集映射-->
<!-- column就是数据库中的字段 property就是实体类中的属性-->
<resultMap id="UserMap" type="user">
<result column="id" property="id"></result>
<result column="name" property="name"></result>
<result column="pwd" property="password"></result>
</resultMap>
<select id="getUserList" resultMap="UserMap">
<!-- 执行SQL-->
select * from mybatis.user
</select>
</mapper>
6、日志
6.1、日志工厂
如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手!
曾经:sout、debug
现在:日志工厂

-
SLF4J
-
LOG4J(3.5.9 起废弃) 【掌握】
-
LOG4J2
-
JDK_LOGGING
-
COMMONS_LOGGING
-
STDOUT_LOGGING 【掌握】
-
NO_LOGGING
在Mybatis中具体使用哪一个日志实现,在设置中设定
STDOUT_LOGGING 标准日志输出
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

7、分页

查询从0开始的两个数据

查询从下标为2开始的两个数据

查询前两个数据
使用Mybatis实现分页,核心SQL
-
接口
List<User> getUserByLimit(Map<String,Integer> map);
-
Mapper.xml
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from user limit #{startIndex},#{pageSize}
</select>
-
测试
7.3、分页插件

8、使用注解开发
8.2、

-
测试
8.3、CRUD 注释
我们可以在工具类创建的时候实现自动提交事务。
return sqlSessionFactory.openSession(true);
编写接口,增加注解
package com.chen.dao;
import com.chen.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
//等价于之后使用的mapper
public interface UserMapper {
测试
package com.chen.dao;
import com.chen.pojo.User;
import com.chen.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
public class UserDaoTest {
接口绑定到mybatis-config,可以用*通配
关于@Param()注解
-
基本类型的参数或者String类型需要加上
-
引用类型不需要加
-
如果只有一个基本类型的话,可以忽略,但是建议大家都加上
-
我们在SQL中引用的就是我们这里的@Param()中设定的属性名
9、Lombok
使用不走:
-
在idea中安装lombok
-
在项目中导入lombokjar包
-
在实体类上加注解即可
-
//实体类
@Data:生成

@AllArgsConstructor 有参构造 @NoArgsConstructor 无参构造
10、多对一的处理

建表语句
p19复杂环境的搭建用到的sql语句 CREATE TABLE teacher ( id INT(10) NOT NULL, name VARCHAR(30) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(id, name) VALUES (1, '秦老师');
CREATE TABLE student ( id INT(10) NOT NULL, name VARCHAR(30) DEFAULT NULL, tid INT(10) DEFAULT NULL, PRIMARY KEY (id), KEY fktid (tid), CONSTRAINT fktid FOREIGN KEY (tid) REFERENCES teacher (id) ) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO student (id, name, tid) VALUES ('1', '小明', '1'); INSERT INTO student (id, name, tid) VALUES ('2', '小红', '1'); INSERT INTO student (id, name, tid) VALUES ('3', '小张', '1'); INSERT INTO student (id, name, tid) VALUES ('4', '小李', '1'); INSERT INTO student (id, name, tid) VALUES ('5', '小王', '1');
测试环境搭建
-
导入lombok
-
新建实体类Student,Teacher
-
建立Mapper接口
-
建立Mapper.XMl文件
-
在核心配置文件中绑定注册我们的Mapper接口或者文件
-
测试查询是否能够成功
按照查询嵌套处理
<!--
思路
1.查询所有的学生
2.根据查询出来的学生的tid寻找对应的老师
-->
<select id="getStudent" resultMap="StudentTeacher" >
select * from student;
</select>
<resultMap id="StudentTeacher" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!-- 复杂的属性,我们需要单独处理
对象: association
集合: collection
-->
<association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
按照结果查询处理
<!-- 按照结果嵌套处理-->
<select id="getStudent2" resultMap="StudentTeacher" >
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid=t.id
</select>
<resultMap id="StudentTeacher2" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="name"/>
</association>
</resultMap>
11、一对多的处理
比如:一个老师拥有多个学生!
对于老师而言,就是一对多的关系
环境搭建
实体类
private int id;
private String name;
private int tid;
private int id;
private String name;
//一个老师拥有多个学生
private List<Student> students;
按照嵌套查询
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="teacher" >
<collection property="students" javaType="ArrayList" ofType="stdent" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="student">
select * from student where tid =#{tid}
</select>
</mapper>
按照结果嵌套处理
<!--按结果嵌套查询-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid};
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- javaType=""指定属性的类型-->
<collection property="students" ofType="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
小结
-
关联-association 【多对一】
-
-
javaType & ofType
-
JavaType 用来指定实体类中的属性
-
ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
-
注意点:
-
抱着sql的可读性,尽量保证通俗易懂
-
注意一对多和多对一中,属性名和字段的问题
-
如果问题不好排查错误,可以使用日志,
面试高频
-
mysql引擎
-
InnoDB底层原理
-
索引
-
索引优化
12、动态SQL
什么是动态sql:动态SQL就是指不同的条件生成不同的sql语句
搭建环境
CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8;
创建一个基础工程
-
导包
-
编写配置文件
-
编写实体类
-
编写实体类对于的mapper接口及mapper.xml 文件
备注:<setting name="mapUnderscoreToCamelCase" value="true"/>开启驼峰命名转换
IF

Time(where,set)

where 就是会自动识别是不是第一个然后拼接上where 或and
select * from blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
所谓动态SQL,本质还是SQL语句,只是我们可以在SQL层面去执行一个逻辑代码
SQL片段
有的时候我们可能会将一些公共的部分抽取出来方便复用。
-
使用SQL标签抽取公共部分
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
-
用include引用
<select id="queryBlotIF" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
注意事项:
-
最好基于单表来定义SQL片段
-
不要存在where标签
Foreach
<!-- select * from blog where 1=1 and (id=1 or id=2 or id=3)
我们现在传递一个万能的map,这map可以存在一个集合
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
13、缓存
13.1、简介
查询 : 链接数据库,耗资源!
一次查询的结果,给他一个暂存在一个可以直接取到的地方 -->内存 : 缓存
我们再次查询相同数据的时候,直接走缓存,就不用走数据库

13.2、Mybatis缓存

13.3、一级缓存
-
一级缓存也叫本地环境:SqlSession
-
与数据库同一次会话期间查询到的数据会放在本地缓存中。
-
以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;
-
测试步骤:
-
开启日志
-
测试在一个Session中查询两次相同记录
-
查看日志输出

缓存失效的情况:
-
查询不同的东西

-
增删改操作有可能改变原来的东西所以缓存会失效

-
查询不同的Mapper.xml
-
手动清理缓存
//手动清理缓存
sqlSession.clearCache();

小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段。

浙公网安备 33010602011771号