Mybatis
1.简介
MyBatis 是一款优秀的持久层框架
它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
如何获得Mybaties?
- maven
- Github:https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.5.2
- 中文文档:https://mybatis.org/mybatis-3/index.html
resources目录
&符号xml中转义 &
2.第一个Mybatis程序
思路:搭建环境------>导入Mybatis------>编写代码------>测试
2.1、搭建环境
搭建数据库
新建项目:
-
新建一个普通的maven项目
-
删除src目录
-
导入maven依赖
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
2.2、创建一个模块
jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
-
编写mybatis的核心配置文件
<?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="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="463799"/> </dataSource> </environment> </environments> </configuration>
-
编写mybatis工具类
package com.yang.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; //sqlsessssionfactory--->sqlsession public class mybatisutils { private static SqlSessionFactory sqlSessionFactory; static { try { //使用mybatis 获取sqlsesessionfactory对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getsqlsession(){ SqlSession sqlSession = sqlSessionFactory.openSession(); return sqlSession; } }
2.3、编写代码
-
实体类
-
DAO接口
-
接口实现类
- 返回结果集对应 resultMap或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"> <!--namespace=绑定一个对应的Dao接口--> <mapper namespace="com.yang.Dao.userdao"> <!-- id对应原来的方法名字--> <select id="getUserList" resultType="com.yang.pojo.user"> select * from mybatis.user; </select> </mapper>
2.4、测试
注意点:Type interface com.yang.Dao.userdao is not known to the MapperRegistry.
解决:注册驱动
<!-- 每一个mapper.xml都需要在mybatis的核心配置文件中注册-->
<mappers>
<mapper resource="com/yang/Dao/UserMapper.xml"/>
</mappers>
MapperRegistry是什么?
核心配置文件中注册mappers
Could not find resource mybatis-config.xml或he error may exist in com/yang/Dao/UserMapper.xml
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
- junit测试
3.CRUD
1、namespace中的包名要和DAO/Mapper接口的包名一致
2、select
选择查询语句
- id:就是对应的namespace中的方法名
- resuType:sql语句执行的返回值
- parameterType:参数返回的类型
注意点:增删改需要提交事务
接口方法类型用int
3.万能Map
假设,我们的实体类或者数据库中的表,字段或者参数过多,我们应当考虑使用Map
4.模糊查询
- java代码执行的时候,传递通配符% %
- 在sql拼接中使用通配符,但会有sql注入的危险
4.配置解析
1.核心配置文件
- mybatis-config.xml
- MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息
2.环境变量
MyBatis 可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。
mybatis默认的事务管理器**(transactionManager)**就是JDBC,数据源(dataSource):连接池:POOLED
3.属性(properties)
我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性(db.properties),也可以在 properties 元素的子元素中设置
编写一个配置文件 db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=463799
在核心配置文件中引入
<!-- 引入外部配置文件--> <properties resource="db.properties"/>
引入后的完整核心配置文件
<?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 resource="db.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></environments><!-- 每一个mapper.xml都需要在mybatis的核心配置文件中注册--><mappers> <mapper resource="com/yang/Dao/UserMapper.xml"/></mappers></configuration>
- 可以直接引入外部文件
- 可以在properties其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的,即外部文件db.properties里设置的字段的优先级大于在核心配置文件标签properties里设置的字段
4.类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dXmR1XLk-1628314217816)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20210804125209699.png)]
即在核心配置文件中使用标签,可使用package或typeAlias指定别名
使用package:会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。
@Alias("author")public class Author { ...}
5.设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true | false | false |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
---|---|---|---|
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
6.其它配置
类型处理器(typeHandlers)
对象工厂(objectFactory)
插件(plugins)
- mybatis-plus
- mybatis-generator-core
- 通用mapper
7.映射器(mappers)
1.推荐使用
<!-- 使用相对于类路径的资源引用 --><mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/></mappers>
核心配置文件对应如下:
<mappers> <mapper resource="com/yang/Dao/UserMapper.xml"/></mappers>
2.通过class查对应的接口
<!-- 使用映射器接口实现类的完全限定类名 --><mappers> <mapper class="org.mybatis.builder.AuthorMapper"/> <mapper class="org.mybatis.builder.BlogMapper"/> <mapper class="org.mybatis.builder.PostMapper"/></mappers>
注意点:
- 接口和它的配置文件必须同名
- 接口和它的配置文件必须在同一个包下
3.通过包名查
<!-- 将包内的映射器接口实现全部注册为映射器 --><mappers> <package name="org.mybatis.builder"/></mappers>
注意点:
- 接口和它的配置文件必须同名
- 接口和它的配置文件必须在同一个包下
8.生命周期和作用域
5.解决属性名和字段名不一致的问题->Resultmap
即数据库中的字段名和实体类中属性不一致的情况
resultMap 结果集映射
<select id="getUserList" resultMap="随便取">
<?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=绑定一个对应的Dao接口--><mapper namespace="com.yang.Dao.UserMapper"> <resultMap id="yangpeng" type="user"> <result column="pwd" property="password"/> </resultMap><!-- id对应原来的方法名字--> <select id="getUserList" resultMap="yangpeng"> select * from mybatis.user; </select></mapper>
6.日志
6.1日志工厂
如果一个数据库操作,出现了异常,我们需要排错,日志就是最好的助手
曾经排错:sout 、debug
现在:日志工厂
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
---|
- SLF4J【掌握】
- LOG4J 【掌握】
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING 【掌握】 控制台输出
- NO_LOGGING
在核心配置文件中设置如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rEakBtqx-1628314217819)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20210804173404726.png)]
注意点:不能有空格,大小写要一致
6.2、LOG4J
通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
- 先导入LOG4J 的包
- log4j.properties
- 配置log4j为日志实现
log4j的简单使用:
-
导入包import org.apache.log4j.Logger;
-
日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(userTest.class);
-
日志级别
7.分页
使用limit分页
使用Mybatis实现分页,核心sql
分页插件:PageHelper
8.使用注解开发
- 注解在接口上实现
- 需要在核心配置文件中绑定接口
- @Param() 方法存在多个参数,所有参数前面必须加上@Param()
- 基本类型的参数或者String类型需要加上
- 引用类型不需要加
- 如果只有一个基本类型,可以忽略,但建议加上
- 我们在SQL中引用的技术我们这里的@Param("")中设置的属性名
9.Lombok 在实体类使用
- 下载插件
- 导包
<!-- https://mvnrepository.com/artifact/io.mateu/lombok --><dependency> <groupId>io.mateu</groupId> <artifactId>lombok</artifactId> <version>1.18.11.97</version></dependency>
@Data:包括无参构造,get 、set、tostring、hashcode、equals等
@AllArgsConStructor 有参构造
@NoArgsConStructor 无参构造
10.多对一处理
实体类:
public class Student { private int id; private String name; //学生需要关联一个老师 private Teacher teacher;
public class Teacher { private int id; private String name;
按照查询嵌套处理
复杂的属性我们需要单独处理
对象:association
集合:collection
<?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=绑定一个对应的Dao接口--><mapper namespace="com.yang.Dao.StudentMapper"><!-- <select id="getstudent" resultType="Student">--><!-- select * from student--><!-- </select>--> <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></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"><!--namespace=绑定一个对应的Dao接口--><mapper namespace="com.yang.Dao.StudentMapper"><!-- 按照结果嵌套处理--> <select id="getstudent2" resultMap="studentteacher2"> 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="tname"/> </association> </resultMap>=</mapper>
11.一对多处理
实体类
package com.yang.pojo;import java.util.List;public class Teacher { private int id; private String name; //一个老师拥有多个学生 private List<Student> students; public Teacher() { } public Teacher(int id, String name, List<Student> students) { this.id = id; this.name = name; this.students = students; } 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 List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } @Override public String toString() { return "Teacher{" + "id=" + id + ", name='" + name + '\'' + ", students=" + students + '}'; }}
package com.yang.pojo;public class Student { private int id; private String name; private int tid; public Student() { } public Student(int id, String name, int tid) { this.id = id; this.name = name; this.tid = tid; } 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 int getTid() { return tid; } public void setTid(int tid) { this.tid = tid; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", tid=" + tid + '}'; }}
xml配置:
集合:collection
javaType:指定属性的类型
集合中的泛型信息我们使用ofType获取
<?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=绑定一个对应的Dao接口--><mapper namespace="com.yang.Dao.TeacherMapper"><select id="getTeacher" resultMap="teacherstudent"> select s.id sid ,s.name sname,t.name tname ,t.id tid from mybatis.student s,mybatis.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"/><!-- 集合:collection javaType:指定属性的类型 集合中的泛型信息我们使用ofType获取--> <collection property="students" ofType="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap></mapper>
小结
1.关联:association 【多对一】
2.集合:collection 【一对多】
3.javaType & ofType
- javaType 用来指定实体类型中属性的类型
- ofType 用来指定映射到List或者集合中的pojo类型,泛型的约束类型
面试高频:
- Mysql引擎
- innodb底层原理
- 索引
- 索引优化
12.动态SQL
什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句
所谓的动态SQL,本质上还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
IF
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=绑定一个对应的Dao接口--><mapper namespace="com.yang.Dao.blogMapper"> <insert id="addBlog" parameterType="blog" > insert into mybatis.blog values (#{id},#{title},#{author},#{createTime},#{views}); </insert><select id="queryBlogIf" parameterType="map" resultType="Blog"> select * from mybatis.blog where 1=1 <if test="title != null"> and title=#{title} </if> <if test="author != null"> and author=#{author} </if></select></mapper>
测试:
@Test public void query(){ SqlSession sqlSession = mybatisutils.getsqlsession(); blogMapper mapper = sqlSession.getMapper(blogMapper.class); HashMap map = new HashMap(); map.put("author", "杨鹏"); List<Blog> blogs = mapper.queryBlogIf(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
choose(when ,otherwise)
trim(where,set)
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="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <include refid="if-title-author"></include> </where></select>
Foreach
13.缓存
13.1 简介
查询 : 连接数据库,耗资源
一次查询的结果,给他暂存一个可以直接取到的地方 --> 内存:缓存
我们再次查询的相同数据的时候,直接走缓存,不走数据库了
什么是缓存[Cache]?
存在内存中的临时数据
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题
为什么使用缓存?
减少和数据库的交互次数,减少系统开销,提高系统效率
什么样的数据可以使用缓存?
经常查询并且不经常改变的数据 【可以使用缓存】
13.2 MyBatis缓存
MyBatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存,缓存可以极大的提高查询效率。
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
默认情况下,只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存。
13.3 一级缓存
- 一级缓存也叫本地缓存:SqlSession
- 与数据库同一次会话期间查询到的数据会放在本地缓存中
- 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库
缓存失效的情况:
- 查询不同的东西
- 增删改操作,可能会改变原来的数据,所以必定会刷新缓存
- 查询不同的Mapper.xml
- 手动清理缓存
13.4 二级缓存
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
基于namespace级别的缓存,一个名称空间,对应一个二级缓存
工作机制
一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
如果会话关闭了,这个会员对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
新的会话查询信息,就可以从二级缓存中获取内容
不同的mapper查询出的数据会放在自己对应的缓存(map)中
一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存。
步骤:
- 开启全局缓存
<!--显示的开启全局缓存--><setting name="cacheEnabled" value="true"/>
-
在Mapper.xml中使用缓存
<!--在当前Mapper.xml中使用二级缓存--><cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
-
测试
问题:我们需要将实体类序列化,否则就会报错
- 只要开启了二级缓存,在同一个Mapper下就有效
- 所有的数据都会放在一级缓存中
- 只有当前会话提交,或者关闭的时候,才会提交到二级缓存中
13.5 缓存原理
13.6 自定义缓存-ehcache
-
导包
<dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</version></dependency>
-
在mapper中指定使用我们的ehcache缓存实现
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>