- 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(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
https://mybatis.org/mybatis-3/zh/configuration.html#environments
MyBatis可以配置多种运行环境,但是每一个sqlSessionFactory实例只能选择一套环境
MyBatis默认事务管理器是JDBC(可选managed),连接池:pooled(可选unpooled)
我们可以用属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置【db.properties】
在中引用
- 可以直接引入外部文件
- 可以在其中增加一些属性
- 两个文件有同样的key,优先使用的配置
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
当这样配置时, 可以用在任何使用 的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
每一个在包 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 的别名为 ;若有注解,则别名为其注解值。见下面的例子:
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- mybatis-plus. mybatis增强工具
- Mybatis-generator-core
- 通用mapper
**MapperRegistry:**在注册绑定mapper
注:也可以尝试在resources下创建相同路径的文件夹,把xml文件放进去实现分离,不过需要一个文件夹一个文件夹创建
生命周期和作用域至关重要,错误的使用可能会导致非常严重的并发问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XHl3fEaF-1588921857557)(MyBatis.assets/截屏2020-04-26 下午5.43.01.png)]
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
- 一旦创建,就不再需要
- 局部变量
SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
- 可以想象成数据库连接池
- 使用单例或者静态单例模式
SqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) { // 你的应用逻辑代码 }
在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。
- 链接到连接池的一个请求
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
- 请求结束需要关闭
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ofusbURy-1588921857559)(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-1588921857560)(MyBatis.assets/640.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2fgDhsTO-1588921857562)(MyBatis.assets/640-20200427121138344.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-1588921857563)(MyBatis.assets/截屏2020-04-28 下午4.27.34.png)]
缓存顺序:
- 先看二级缓存中有没有
- 在看一级缓存中有没有
- 查询数据集
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/33145.html