- MyBatis 是一款优秀的持久层框架.
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- Maven仓库
- Github:https://github.com/mybatis/mybatis-3/releases
- 中文文档:https://mybatis.org/mybatis-3/zh/index.html
- 数据持久化:将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(JDBC),IO文件持久化
Dao层,Service层,Controller层
- 完成持久化工具的代码块
- 层是界限十分明显的
- 优点
- 简单易学,零花
- SQL与代码分离,提高可维护性
- 提供映射标签,支持对象与数据库的ORM字段关系映射
- 提供对象映射标签,支持对象关系组件维护
- 提供xml标签,支持编写动态SQL
- MySQL数据库:
- 创建一个普通maven项目
- 删除src目录
- 导入maven依赖
- 编写mybatis核心配置文件
- 编写mybatis工具类
- 编写myBatis工具类
- UserDao
- 接口实现类从原来的UserDaoImpl转变为一个Mapper配置文件
注意点:
org.apache.ibatis.binding.BindingException: Type interface com.neil.dao.UserDao is not known to the MapperRegistry.
MapperRegistry:
需要在中配置
测试最好使用try包裹起来
namespace中的包名需要和mapper的接口名字一样
- 编写接口
- 编写mapper.xml
- 测试(增删改需要提交事务)
选择,查询语句:
- id:就是对应的namespace中的方法名字:
- resultType:sql语句执行的返回值
假设实体类或者数据库中的表,字段或者参数过多,我们应当考虑使用Map!
直接在sql中取出key即可,对象成为参数,需要直接从sql中取对象的属性
- 接口:
- mapper
- Test
两种方式,需要注意SQL注入问题
- Java代码执行的时候,传递通配符%%
- 在SQL拼接的时候使用通配符
- MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
- configuration(配置)
</li></ul><ul data-indent="2"><li>properties(属性)</li><li>settings(设置)</li><li>typeAliases(类型别名)</li><li>typeHandlers(类型处理器)</li><li>objectFactory(对象工厂)</li><li>plugins(插件)</li><li>environments(环境配置) </li></ul><ul data-indent="3"><li>environment(环境变量) </li></ul><ul data-indent="4"><li>transactionManager(事务管理器)</li><li>dataSource(数据源)</li></ul><ul data-indent="2"><li>databaseIdProvider(数据库厂商标识)</li><li>mappers(映射器)</li></ul><p>https://mybatis.org/mybatis-3/zh/configuration.html#environments</p><p>MyBatis可以配置多种运行环境,<strong>但是每一个sqlSessionFactory实例只能选择一套环境</strong></p><p>MyBatis默认事务管理器是JDBC(可选managed),连接池:pooled(可选unpooled)</p><p>我们可以用属性来实现引用配置文件</p><p>这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置【db.properties】</p><div></div><p>在中引用</p><div></div><ul><li>可以直接引入外部文件</li><li>可以在其中增加一些属性</li><li>两个文件有同样的key,优先使用的配置</li></ul><p>类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:</p><div></div><p>当这样配置时, 可以用在任何使用 的地方。</p><p>也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:</p><div></div><p>每一个在包 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 的别名为 ;若有注解,则别名为其注解值。见下面的例子:</p><div></div><ul><li>typeHandlers(类型处理器)</li><li>objectFactory(对象工厂)</li><li>plugins(插件)</li></ul><ul data-indent="1"><li>mybatis-plus. mybatis增强工具</li><li>Mybatis-generator-core</li><li>通用mapper</li></ul><p>MapperRegistry:在注册绑定mapper</p><div></div><p>注:也可以尝试在resources下创建相同路径的文件夹,把xml文件放进去实现分离,不过需要一个文件夹一个文件夹创建</p><p>生命周期和作用域至关重要,错误的使用可能会导致非常严重的<strong>并发问题</strong></p><p>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XHl3fEaF-1588921857557)(MyBatis.assets/截屏2020-04-26 下午5.43.01.png)]</p><h5>SqlSessionFactoryBuilder</h5><blockquote style="margin-top: 5px; margin-bottom: 5px; padding-left: 1em; margin-left: 0px; border-left: 3px solid rgb(238, 238, 238); opacity: 0.6;"><p>这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的**作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。</p></blockquote><ul><li>一旦创建,就不再需要</li><li>局部变量</li></ul><h5>SqlSessionFactory</h5><blockquote style="margin-top: 5px; margin-bottom: 5px; padding-left: 1em; margin-left: 0px; border-left: 3px solid rgb(238, 238, 238); opacity: 0.6;"><p>SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的**实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的**作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。</p></blockquote><ul><li>可以想象成数据库连接池</li><li>使用单例或者静态单例模式</li></ul><h5>SqlSession</h5><blockquote style="margin-top: 5px; margin-bottom: 5px; padding-left: 1em; margin-left: 0px; border-left: 3px solid rgb(238, 238, 238); opacity: 0.6;"><p>每个线程都应该有它自己的 SqlSession 实例。<strong>SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的**的作用域是请求或方法作用域</strong>。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:</p><p>try (SqlSession session = sqlSessionFactory.openSession()) {
讯享网// 你的应用逻辑代码 }
在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。
- 链接到连接池的一个请求
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的**的作用域是请求或方法作用域
- 请求结束需要关闭
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ofusbURy-59)(MyBatis.assets/截屏2020-04-26 下午5.49.17.png)]
这里面每一个Mapper就代表一个具体的业务
新建一个项目,拷贝之前的,测试实体类字段不一样
此时私有属性与数据库字段不一样,有几种解决方式:
- 数据库查询取别名,使其更改为私有属性的名称一致
- resultMap
- 元素是MyBatis中最重要最强大的元素
- 的设计思想是,对于简单的语句根本不需要配置显示进行映射结果集,而对于复杂一点的语句只需要描述他们的关系就可以了
- 最优秀的地方在于,有时候不需要直接定义
在设置中有如下设置来设置日志工厂
STDOUT_LOGGING为标准日志输出
在中配置
- 导入jar包
- 配置文件编写
在resources建立
- 在中配置
- 在程序中使用Log4j进行输出!
思考:为什么需要分页?
在学习mybatis等持久层框架的时候,会经常对数据进行增删改查操作,使用最多的是对数据库进行查询操作,如果查询大量数据的时候,我们往往使用分页进行查询,也就是每次处理小部分数据,这样对数据库压力就在可控范围内。
核心思想:将需要分页的信息通过Map的方式传入UserMapper.xml,之后拼接字符串
步骤:
- mapper文件
- Mapper接口,参数为map
- 在测试类中传入参数测试
步骤:
- mapper接口
- mapper文件
- 测试类
官方文档:https://pagehelper.github.io/
- 大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
- 根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好
- 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
- 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
关于接口的理解
- 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
- 接口的本身反映了系统设计人员对系统的抽象理解。
- 接口应有两类:
- 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);
- 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface);
- 一个体有可能有多个抽象面。抽象体与抽象面是有区别的。
- mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到MyBatis 3提供了新的基于注解的配置。不幸的是,Java 注解的的表达力和灵活性十分有限。最强大的 MyBatis 映射并不能用注解来构建
- sql 类型主要分成 :
- @select ()
- @update ()
- @Insert ()
- @delete ()
- 注意:利用注解开发就不需要mapper.xml映射文件了 .
步骤:
- 在接口中添加注解
- 在mybatis的核心配置 文件中注入
- 测试
使用注解开发本质上是实现了jvm的动态代理机制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mlavtY22-60)(MyBatis.assets/640.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2fgDhsTO-62)(MyBatis.assets/640-.png)]
改造MybatisUtils工具类的getSession( ) 方法,重载实现。
【注意】确保实体类和数据库字段对应
查询:
- 编写接口方法注解
- 测试
新增:
- 编写接口方法注解
- 测试
@Param注解用于给方法参数起一个名字。以下是总结的使用原则:
- 在方法只接受一个参数的情况下,可以不使用@Param。
- 在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
- 如果参数是 JavaBean , 则不能使用@Param。
- 不使用@Param注解时,参数只能有一个,并且是Javabean。
- #{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符? 【推荐使用】
- ${} 的作用是直接进行字符串替换 【不安全,可能还会有SQL注入问题】
使用步骤:
- 在IDEA插件安装Lombok
- 导入maven依赖
- 案例
- 常用注解
注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
:注解在属性上;为属性提供 setting 方法
:注解在属性上;为属性提供 getting 方法
:注解在类上;为类提供一个 属性名为log 的 log4j 日志对象
:注解在类上;为类提供一个无参的构造方法
:注解在类上;为类提供一个全参的构造方法
: 可以关闭流
: 被注解的类加个构造者模式
: 加个同步锁
: 等同于try/catch 捕获异常
: 如果给参数加个这个注解 参数为null会抛出空指针异常
: 注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法:表示在mapper.xml文件中对应的ResultMap的Id值
来源:
- 导入lombok
- 创建实体类Teacher, Student(已忽略getter/setter)
- 建立Mapper接口
- 建立Mapper.xml文件
- 在核心配置文件中绑定注册Mapper接口或文件
- 测试查询

按照查询进行嵌套处理就像SQL中的子查询
按照结果进行嵌套处理就像SQL中的联表查询
比如,一个老师拥有多个学生
对于老师而言就是一对多的关系
实体类:
1、关联-association
2、集合-collection
3、所以association是用于一对一和多对一,而collection是用于一对多的关系
4、JavaType和ofType都是用来指定对象类型的
- JavaType是用来指定pojo中属性的类型
- ofType指定的是映射到list集合属性中pojo的类型。
注意说明:
1、保证SQL的可读性,尽量通俗易懂
2、根据实际要求,尽量编写性能更高的SQL语句

3、注意属性名和字段不一致的问题
4、注意一对多和多对一 中:字段和属性对应的问题
5、尽量使用Log4j,通过日志来查看自己的错误
动态SQL就是根据不同的条件生成不同的SQL语句
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
12.1、搭建环境
数据库:
pojo:
BlogMapper.xml
测试类:
接口:
BlogMapper.xml
测试类:
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
where:只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
choose:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,
set:在下面的例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面执行逻辑代码
有的时候我们会把一些公共的部分抽取出来方便复用
结果与上例一样
注意事项:
- 最好基于单表定义SQL片段
- 不要存在where标签
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
- 什么是缓存?
- 存在内存中的临时数据
- 将用户经常查询的数据放在缓存(内存中),将用户查询的数据不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题
- 为什么要使用缓存?
- 减少和数据库交互的次数,减少系统开销,提高系统效率。
- 什么 样的数据能够使用缓存?
- 经常查询并且不经常改变的数据
- Mybatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大提升查询效率
- Myabtis默认提供了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(sqlSession级别的缓存,也称为本地缓存)
- 二级缓存需要手动开启,他是基于namespace级别的缓存
- 为了提高扩展性,Mybatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存
- 一级缓存也叫本地缓存:sqlSession(从开启到sqlSession.close())
- 与数据库用一次会话期间查询到的数据会放在本地缓存中。
- 以后如果要获取想通的数据,直接从缓存里面拿,没有必要再去查询数据库
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
缓存失效情况:
- 查询不同的东西
- 增删改操作
- 手动清理缓存
小结:一级缓存默认开启,只在一次SqlSession中有效,无法关闭。一级缓存相当于一个Map
- 二级缓存也叫全局缓存,一级缓存的作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存:
- 工作机制:
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
- 如果当前会话关闭了,一级缓存就消失了。不过我们想要的是,会话关闭之后,一级缓存的数据被保存在二级缓存之中
- 新的会话查询消息,可以直接从二级缓存中读取内容
- 不同的mapper查处的数据会放在对应的缓存中
步骤:
- 开启二级缓存
- 在*Mapper.xml中增加标签
- – 最近最少使用:移除最长时间不被使用的对象。
- – 先进先出:按对象进入缓存的顺序来移除它们。
- – 软引用:基于垃圾回收器状态和软引用规则移除对象。
- – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
- 也可以在查询标签中设置
注意:pojo最好实现序列化接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FzT7NAgi-63)(MyBatis.assets/截屏2020-04-28 下午4.27.34.png)]
缓存顺序:
- 先看二级缓存中有没有
- 在看一级缓存中有没有
- 查询数据集


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/198694.html