网络营销百科,seo快速排名软件案例,文化类网站建设方向,网站seo诊断分析和优化方案前言
本文主要学习Mybatis相关标签的使用及Mybatis的工作流程。
文中用到的示例#xff0c;代码存储位置#xff1a;
GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples父工程Java_Framework_Mybatis
基础
示例 | 初始Mybatis
数据库初始化
-- 建表
CREATE…前言
本文主要学习Mybatis相关标签的使用及Mybatis的工作流程。
文中用到的示例代码存储位置
GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples父工程Java_Framework_Mybatis
基础
示例 | 初始Mybatis
数据库初始化
-- 建表
CREATE TABLE user(
id INT(20) NOT NULL PRIMARY KEY,
name VARCHAR(30) DEFAULT NULL,
pwd VARCHAR(30) DEFAULT NULL
)ENGINEINNODB DEFAULT CHARSETutf8;-- 插入语句
INSERT INTO user(id, name, pwd) VALUES
(1, 狂神, 123456),
(2, 张三, 1234567),
(3, 李四, 1234568)项目目录及内容 UserDaoDao接口提供获取数据库数据的接口方法UserMapper.xmlDao接口对应的配置文件每个接口方法都有对应的具体SQL语句User数据库对象MybatisUtils每次连接数据库之前都需要通过sqlSessionFactory来获取sqlSession对象从而进行后续的数据库连接、sql执行、关闭操作可以理解为获取Dao接口的代理类对象已经对接口方法进行增强能运行相应的SQL语句及返回查询结果mybatis-config.xmlmybatis的配置文件用于定义数据库的配置连接、Mapper的注册将Dao接口与对应的xml文件相关联UserTest测试文件
常见问题汇总 Dao层Mapper.xml配置文件没有在mybatis-config.xml中注册 maven导出资源问题资源不放在resources文件夹下正常情况下没法输出到target文件夹中。通过配置资源导出的目录解决该问题。 通过设置src/main/resources和src/main/java目录下的所有.xml文件和.properties文件都会被识别为资源从而在构建的时候输出到target目录
!-- 在项目的pom.xml文件中加入此配置 --buildresourcesresourcedirectorysrc/main/resources/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includes/resourceresourcedirectorysrc/main/java/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includes/resource/resources
/build示例 | 上述示例完善
调整后的目录结构 log存放日志的文件夹db.properties将数据库连接配置放在该配置文件中提供一个key-value的访问结构在mybatis-config.xml中导入后可以通过变量标识符${}替换相应的连接对象log4j.propertiesMaven导入日志依赖、mybatis-config.xml中开启日志log4j.properties配置文件配置日志细节名字是默认的放在resources目录下就能访问到不同的日志实现配置文件的默认名字也不一样
相关改动细节 通过db.properties配置数据库连接不再需要转义符了 mybatis-config.xml 配置多套数据库环境映射Mapper的三种方式 UserDao.xmlresultMap标签解决数据库字段与poji实体字段不一致的情况
示例 | 基于注解开发上述示例
项目目录结构 UserMapper.xml文件去掉了转而在UserMapper.java中加入注解实现SQL语句。
**注意**即使没了UserMapper.xml配置文件也要在mybatis-config.xml配置文件中注册mapper
进阶
示例 | resultMap多对一处理
项目目录结构 Pojo中增加了学生和老师的实体对象。 案例背景及概念理解关联、集合
在学校里一个老师对应多个学生。
对于学生而言是多对一的关系多个学生关联一个老师对于老师而言是一对多的关系一个老师集合多个学生
现在要求查询所有的学生及其关联的老师信息
数据库创建
-- 新建老师表
CREATE TABLE teacher (id INT(10) NOT NULL,name VARCHAR(30) DEFAULT NULL,PRIMARY KEY (id)
) ENGINEINNODB DEFAULT CHARSETutf8-- 插入老师数据
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)
) ENGINEINNODB DEFAULT CHARSETutf8-- 插入学生数据
INSERT INTO student (id, name, tid) VALUES
(1, 小明, 1),
(2, 小红, 1),
(3, 小张, 1),
(4, 小李, 1),
(5, 小王, 1)复杂查询的两种查询思路
子查询 | 按照查询嵌套处理先查询学生为每一个查询到的学生查询其对应的老师。
-- 对应的SQL写法
select id, name, tid, (select name from teacher as t where t.id s.tid) as t_name from student s;select idgetTeacher resultTypeGSF.Example.Pojo.Teacherselect * from learn_mybatis.teacher where id#{id}
/select!--根据查询嵌套处理--
select idgetStudent resultMapgetStudentselect id, name, tid from learn_mybatis.student;
/selectresultMap idgetStudent typeGSF.Example.Pojo.Studentresult propertyid columnid/result propertyname columnname/association propertyteacher columntid javaTypeGSF.Example.Pojo.Teacher selectgetTeacher/
/resultMap连接查询 | 按照结果嵌套处理先查询所有的学生、老师然后封装查询结果
select s.id s_id ,s.name s_name, t.id t_id, t.name t_name
from learn_mybatis.student s, learn_mybatis.teacher t
where s.tidt.idselect idgetStudent2 resultMapgetStudent2select s.id s_id ,s.name s_name, t.id t_id, t.name t_name from learn_mybatis.student s, learn_mybatis.teacher twhere s.tidt.id
/selectresultMap idgetStudent2 typeGSF.Example.Pojo.Studentresult propertyid columns_id/result propertyname columns_name/association propertyteacher javaTypeGSF.Example.Pojo.Teacherresult propertyid columnt_id/result propertyname columnt_name//association
/resultMap测试结果
Student(id1, name小明, teacherTeacher(id1, name秦老师))
Student(id2, name小红, teacherTeacher(id1, name秦老师))
Student(id3, name小张, teacherTeacher(id1, name秦老师))
Student(id4, name小李, teacherTeacher(id1, name秦老师))
Student(id5, name小王, teacherTeacher(id1, name秦老师))总结association标签
association标签处理关联关系即多对一关系
示例 | resultMap一对多处理
项目目录结构
同上述示例。 案例背景及概念理解关联、集合
同上述示例。
现在要求查询所有的老师及其集合的学生信息 复杂查询的两种查询思路
子查询 | 按照查询嵌套处理先查询老师为每一个查询到的学生查询其对应的老师。
-- 对应的SQL写法好像没法写-- 上述多对一关系中的写法关注点在学生
-- 这个写法也是有隐患的当一个学生对应多个老师的时候同样会报错
select id, name, tid, (select name from teacher as t where t.id s.tid) as t_name from student s;-- 尝试的写法关注点在老师。直接报错
-- 这样的子查询写法在()中语句返回不是单个值的时候会出现错误因为select后的子查询通常希望返回单个值。
select id, name, (select name from student as s where s.tid t.id) as s_name from teacher as t;-- 总的来说还是用连接查询要好点理解简单还不容易出错效率还高select idgetTeacher2 resultMapTeacherStudent2select * from learn_mybatis.teacher where id#{id}
/selectresultMap idTeacherStudent2 typeGSF.Example.Pojo.Teacher!--两个地方用到id这个result就得写出来不然不展示老师的id--result propertyid columnid/result propertyname columnname/collection propertystudents columnid javaTypeArrayList ofTypeGSF.Example.Pojo.Student selectgetStudentByTeacherId/
/resultMapselect idgetStudentByTeacherId resultTypeGSF.Example.Pojo.Studentselect * from learn_mybatis.student where tid #{id}
/select连接查询 | 按照结果嵌套处理先查询所有的学生、老师然后封装查询结果
select s.id s_id, s.name s_name, t.name t_name, t.id t_id
from learn_mybatis.student s, learn_mybatis.teacher t
where s.tid t.idselect idgetTeacher resultMapgetTeacherselect s.id s_id, s.name s_name, t.name t_name, t.id t_idfrom learn_mybatis.student s, learn_mybatis.teacher twhere s.tid t.id and t.id#{id}
/selectresultMap idgetTeacher typeGSF.Example.Pojo.Teacherresult propertyid columnt_id/result propertyname columnt_name/collection propertystudents javaTypeArrayList ofTypeGSF.Example.Pojo.Studentresult propertyid columns_id/result propertyname columns_name/result propertytid columnt_id//collection
/resultMap测试结果
Teacher(id1, name秦老师, students[Student(id1, name小明, tid1), Student(id2, name小红, tid1), Student(id3, name小张, tid1), Student(id4, name小李, tid1), Student(id5, name小王, tid1)])总结collection标签
collection标签处理集合关系即一对多关系
进阶 | 动态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 浏览量
)ENGINEINNODB DEFAULT CHARSETutf8INSERT INTO blog(id,title,author,create_time,views) VALUES
(1, 如何学Python, 青, 2022-10-11, 300),
(2, 如何学Java, 刘, 2022-10-12, 400),
(3, 如何学Django, 郭, 2022-10-13, 700)动态SQL-IF
public interface UserDao {ListBlog getBlogIf(MapString, Object map);
}select idgetBlogIf parameterTypemap resultTypeGSF.Example.Pojo.Blogselect * from learn_mybatis.blog where 11if testtitle ! nulland title#{title}/ifif testauthor ! nulland author#{author}/if
/selectIF标签不具备自动添加and的功能每个拼接的子SQL语句需要自行添加and
-- 若传入空的map真实的sql语句
select * from learn_mybatis.blog where 11-- 若传入的map带有title键真实的sql语句
select * from learn_mybatis.blog where 11 and title?-- 若传入的map带有title键和author键真实的sql语句
select * from learn_mybatis.blog where 11 and title? and author?动态SQL-where、choose、when、otherwise
public interface UserDao {ListBlog getBlogChoose_When_Otherwise(MapString, Object map);
}select idgetBlogChoose_When_Otherwise parameterTypemap resultTypeGSF.Example.Pojo.Blogselect * from learn_mybatis.blog!-- 这里用到了下一个查询才讲述的where标签 --wherechoosewhen testtitle ! nulland title #{title}/whenwhen testauthor !nulland author #{author}/whenotherwiseand id 1/otherwise/choose/where
/selectchoose、when、otherwisel类似java的switch用法从上到下的判断语句遇到满足的就用即使后续有条件也满足也不会调用where标签具备自动添加where字符和删除首个子SQL语句的and字符的功能
-- 若传入空的map真实的sql语句
select * from learn_mybatis.blog where id1-- 若传入的map带有title键真实的sql语句
select * from learn_mybatis.blog where title?-- 若传入的map带有title键和author键真实的sql语句
select * from learn_mybatis.blog where title?动态SQL-Set
public interface UserDao {int updateBlogSet(MapString, Object map);
}update idupdateBlogSet parameterTypemapupdate learn_mybatis.blogsetif testtitle ! nulltitle #{title},/ifif testauthor ! nullauthor #{author},/if/setwhere id #{id}
/updateset标签具备补充set字符和删除sql语句末尾“,”字符的功能if标签中sql子句末尾的“,”需要写入不然sql语句报错
-- 若传入空的map或仅仅有id的map真实的sql语句
报错-- 若传入的map带有title键真实的sql语句
update learn_mybatis.blog SET title ? where id ?-- 若传入的map带有title键和author键真实的sql语句
update learn_mybatis.blog SET title ?, author ? where id ?动态SQL-trim、sql片段
public interface UserDao {int updateBlogTrim(MapString, Object map);
}sql idif-title-authorif testtitle ! nulltitle #{title},/ifif testauthor ! nullauthor #{author},/if
/sqlupdate idupdateBlogTrim parameterTypemapupdate learn_mybatis.blogtrim prefixSET suffixOverrides,include refidif-title-author/include/trimwhere id #{id}
/update-- 若传入空的map或仅仅有id的map真实的sql语句
报错-- 若传入的map带有title键真实的sql语句
update learn_mybatis.blog SET title ? where id ?-- 若传入的map带有title键和author键真实的sql语句
update learn_mybatis.blog SET title ?, author ? where id ?trim标签可以自定义待拼接sql语句的相关前缀、后缀的补充操作及去除操作上述用trim标签实现set标签的相关功能
trim标签属性描述prefix给sql语句拼接的前缀suffix给sql语句拼接的后缀prefixOverrides去除sql语句前面的关键字或者字符假设该属性指定为AND当sql语句的开头为ANDtrim标签将会去除该ANDsuffixOverrides去除sql语句后面的关键字或者字符假设该属性指定为,“当sql语句的结尾为”,“trim标签将会去除该”,
动态SQL-foreach
public interface UserDao {ListBlog getBlogForeach(MapString, Object map);
}select idgetBlogForeach parameterTypemap resultTypeGSF.Example.Pojo.Blogselect * from learn_mybatis.blogwhereforeach collectionids itemid openand ( close) separatororid#{id}/foreach/where
/select提供遍历操作还是传入的map只是map的键对应的值是一个list
-- 若传入空的map真实的sql语句
select * from learn_mybatis.blog-- 若传入的map中的list带有值1真实的sql语句
select * from learn_mybatis.blog WHERE ( id? )-- 若传入的map中的list带有值1、2、3真实的sql语句
select * from learn_mybatis.blog WHERE ( id? or id? or id? )进阶 | 缓存
缓存的概念
什么是缓存
存在内存中的临时数据。将用户经常查询的数据放在缓存内存中用户去查询数据就不用了从磁盘上关系型数据库数据文件查询而是从缓存中查询从而提高查询效率解决了高并发系统的性能问题。
为什么使用缓存
减少和数据库的交互次数较少系统开销提高系统效率
什么样的数据能使用缓存
经常查询而且不经常改变的数据
Mybatis缓存
MyBatis包含一个非常强大的查询缓存特性它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存一级缓存和二级缓存
默认情况下只有一级缓存开启 (SqlSession级别的缓存也称为本地缓存)二级缓存需要手动开启和配置他是基于namespace级别的缓存为了提高扩展性MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存学到了再说
一级缓存 与数据库同一次会话期间查询到的数据会放在本地缓存中以后如果需要获取相同的数据直接从缓存中拿没必须再去查询数据库 测试验证一级缓存
Test
public void test(){SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.queryUserById(1);System.out.println(user);System.out.println();User user2 mapper.queryUserById(1);System.out.println(user2);// true返回结果为true且只执行了一次sql语句System.out.println(useruser2);sqlSession.close();
}一级缓存失效条件
查询不同的东西增删改操作可能会改变原来的数据所以必定会刷新缓存查询不同的Mapper.xml手动清理缓存
Test
public void test(){SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.queryUserById(1);System.out.println(user);// 更新数据导致缓存时效//mapper.updateUser(new User(2,niahoooo,309487));// 手动清理缓存导致缓存时效//sqlSession.clearCache();System.out.println();User user2 mapper.queryUserById(1);System.out.println(user2);System.out.println(useruser2);sqlSession.close();
}一级缓存生命周期
生命周期为一个特定mapper.xml的一次sqlsession会话
二级缓存 二级缓存也叫全局缓存一级缓存作用域太低了所以诞生了二级缓存 基于namespace级别的缓存一个名称空间对应一个二级缓存 工作机制 一个会话查询一条数据这个数据就会被放在当前会话的一级缓存中如果当前会话关闭了这个会话对应的一级缓存就没了一级缓存中的数据被保存到二级缓存中新的会话查询信息就可以从二级缓存中获取内容不同的mapper.xml查出的数据会放在自己对应的缓存(map)中 测试验证二级缓存
在全局开启二级缓存mybatis-config.xml
setting namecacheEnable valuetrue/在要开启缓存的mapper.xml中开启
cache evictionFIFOflushInterval60000size512readOnlytrue/测试
Test
public void test(){SqlSession sqlSession MybatisUtils.getSqlSession();SqlSession sqlSession2 MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.queryUserById(1);System.out.println(user);UserMapper mapper2 sqlSession2.getMapper(UserMapper.class);User user2 mapper.queryUserById(1);System.out.println(user2);System.out.println(useruser2);sqlSession.close();sqlSession2.close();
}注意事项
我们需要将实体类序列化(实现Serializable接口)否则就会报错sqlsession关闭的时候一定要在最后关闭不能先关闭sqlsession再关闭sqlsession2这样会导致Cause: org.apache.ibatis.executor.ExecutorException: Executor was closed
二级缓存的生命周期
在同一个Mapper.xml下的多次Sqlsession
只有当sqlsession关闭的时候数据才会从一级缓存扔到二级缓存
自定义二级缓存-ehcache
EhCache 是一个纯Java的进程内缓存框架具有快速、精干等特点是Hibernate中默认的CacheProviderEhcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存
具体使用用到再说开发中常用Redis数据库来做缓存。
Mybatis缓存的调用顺序
先看二级缓存中有没有再看一级缓存中有没有查询数据库查询后将数据放入一级缓存