目录
1、什么是MyBatis?
1.1 如何获取MyBatis
1.2 持久化
1.3 持久层
1.4 为什么需要MyBatis?
2、第一个MyBatis程序
2.1 环境搭建
2.2 创建一个模块
2.3 编写代码
2.4 测试
3、CRUD
1、编写接口
2、写sql
3、测试
4、增删改查
5、Map使用
6、模糊查询
4、配置解析
1、核心配置文件
2、配置环境(environments)
3、属性(properties)
4、类型别名(typeAliases)
5、设置
6、注册映射器(mappers)
7、生命周期和作用域(Scope)
5、解决字段和属性不一致问题
6、日志
6.1 日志工厂
6.1 LOG4J
7、分页
7.1 Limit分页
7.2 RowBounds分页
8、注解开发
9、Lombok
10、测试多对一
环境搭建
按照查询嵌套处理
按照结果嵌套处理
11、一对多
环境搭建
按照查询嵌套处理
按照结果嵌套处理
映射小结
12、动态SQL
搭建环境
if
trim(where、set)
choose、when、otherwise
sql片段
forEach
13、缓存
一级缓存
二级缓存
缓存原理
1、什么是MyBatis?
MyBatis概念:
MyBatis 是一款优秀的持久层框架。
它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
MyBatis 历史:
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](Google_百度百科 code/2346604),并且改名为MyBatis 。2013年11月迁移到Github。
1.1 如何获取MyBatis
下载链接:
GitHub - mybatis/mybatis-3: MyBatis SQL mapper framework for Java
maven:导入依赖
1.2 持久化
数据持久化:
概念:持久化就是将程序的数据在持久状态和瞬时状态转化的过程。
内存:断电了就失去了。
出现过的持久化:数据库(JDBC),IO文件持久化。
持久化生活中的例子:冷藏的冰淇淋,密封猫罐头。
为什么需要持久化呢?
因为有一些对象,不能让它丢掉,其次就是内存比较昂贵。
1.3 持久层
出现过的层:Dao层,Service层,Controller层(控制)。
作用:
持久层一般指把数据保存到数据库里。完成持久化工作的代码块。层界限十分明显。1.4 为什么需要MyBatis? MyBatis可以帮助程序员将数据存入到数据库中。方便。传统的JDBC代码太复杂。MyBatis简化,框架,自动化。不用MyBatis其实也可以。其次就是MyBatis也容易上手。
MyBatis优点:
简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。提供映射标签,支持对象与数据库的orm字段关系映射。提供对象关系映射标签,支持对象关系组建维护。提供xml标签,支持编写动态sql。使用的人多。
2、第一个MyBatis程序 2.1 环境搭建
1、搭建数据库
create database mybatis;use mybatis;create table user( id int primary key not null , name varchar(30) default null , pwd varchar(30) default null)engine=innodb charset=utf8;insert into user(id,name,pwd)values (1,'张三',123456),(2,'李四',123456),(3,'赵五',123456)
2、 新建项目
新建一个maven项目删除src目录(可选)导入maven依赖:2.2 创建一个模块
1、编写mybatis核心的配置文件,连接数据库。
修改driver的值:com.mysql.jdbc.Driver
修改url的值:jdbc:mysql://localhost:3306/数据库名?useSSL=true&useUnicode=true&characterEncoding=UTF-8
修改username:root
修改password:123456
2、编写mybatis工具类。
// sqlSessionFactory(sql工厂模式) -->sqlSessionpublic class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; static { // 使用mybatis的第一步,获取sqlSessionFactory对象 try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } // 既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。 // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); // 优化后的 }}
2.3 编写代码
编写实体类:
package com.lei.pojo;// 实体类public class User { private int id; private String name; private String pwd; } // 对应的有参无参构造、setter.getter方法、toString
Dao接口:
package com.lei.dao;import com.lei.pojo.User;import java.util.List;public interface UserDao { List
接口实现类:由原来的UserDaoImpl转换成现在的Dao/Mapper配置文件。
<?xml version="1.0" encoding="UTF-8" ?>
2.4 测试
package com.lei.dao;public class UserDaoTest { @Test public void test() { // 1、获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); try { // 方式一:getMapper 获取UserDao类, UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 通过接口来调用getUserList方法。 List
3、CRUD
设置连接数据库配置文件中的:
namespace="Dao/Mapper接口,具体写Path"。select中的id=方法名。parameterType=参数类型,resultType=返回类型。
1、编写接口
public interface UserMapper { // 根据id查询用户 User getUserById(int id); // 添加一个用户 int addUser(User user); // 修改一个用户 int upDataUser(User user); // 删除一个用户 int deleteUser(int id);}
2、写sql
3、测试
@Testpublic void getUserById() { // 1、获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); // getMapper 获取UserDao类, UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 通过接口来调用getUserById方法。 User userById = mapper.getUserById(1); System.out.println(userById); // 关闭资源 sqlSession.close();}@Test// CRUD的时候需要提交事务public void addUser() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User(4, "赵五", "123444")); // 提交事务 sqlSession.commit(); sqlSession.close();}@Testpublic void updateUser() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.upDataUser(new User(4, "依依", "123666")); sqlSession.commit(); sqlSession.close();}@Testpublic void deleteUser(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.deleteUser(3); sqlSession.commit(); sqlSession.close();}
4、增删改查
不变的三条代码:
SqlSession sqlSession = MyBatisUtils.getSqlSession(); // 获取SqlSession 对象UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 获取UserDao类sqlSession.close();// 关闭资源
4.1增删改
增删改都需要提交事务:
5、Map使用
首先:
Map在获取参数类型的时候传递一个map=parameterType="map" 直接取出key即可。
对象传递参数类型,直接在sql中取出对象的属性即可:parameterType="com.lei.pojo.User"
多个参数可以用map。
1、注册接口
// 万能的Mapint addUser2(Map
2、编写sql
3、测试
@Testpublic void addUser2() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map
注意:数据库字段名和实体类的属性名要一致,如果不一致,则写相对应的名字。
6、模糊查询
测试类:
Java代码执行的时候,传递通配符%%。
List
sql语句内:在sql拼接中使用通配符。
4、配置解析
解析mybatis.xml核心配置文件:
1、核心配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
配置文档的顶层结构如下:
2、配置环境(environments) 3、属性(properties)
我们可以通过properties属性来实现引用配置文件。
概念:这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【properties】
注意点:
properties不能在xml中随便放,它是有顺序的,顺序错了就报错。
外部配置文件dp.properties。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
username=root
password=123456
resources中写配置文件的名称,因为通常都把外部配置文件放到与config同一个包下。在外部配置文件中也可以通过property来写配置文件。在使用配置文件的时候优先使用的是外部配置文件。
4、类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。
它仅用于 XML 配置,意在降低冗余的全限定类名书写。
第一种取别名方式:
第二种取别名方式:
通过包来取别名,它默认的别名就是这个包下的类的名称,首字母小写。
它会扫描pojo包下的所有类。
如果实体类较多,则使用第二种方式好。
第三种:
5、设置
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
具体的mybatis设置请参考官方文档:
配置_MyBatis中文网
6、注册映射器(mappers)
我们MyBatis的配置完成后,我们就可以开始定义SQL映射语句了。
首先:我们需要告诉MyBatis到哪里找到这些语句。
推荐使用以下两个映射:
1.接口和配置文件必须在同一个包下。
2.接口和配置文件必须同名。
这两个映射是写在配置文件中的:
这些配置会告诉 MyBatis 去哪里找映射文件。
写完配置文件后需要在mappers中注册绑定我们配置的Mapper文件。
这个是在核心配置文件中注册:
7、生命周期和作用域(Scope)
作用域和生命周期,是至关重要的,因为错误的使用会导致非常严重的并发问题。
mybatis流程图:
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
它的最佳作用域:局部作用域
SqlSessionFactory
我们可以把SqlSessionFactory想象成一个:数据库连接池
SqlSessionFactory一旦被创建,那就一个在应用的运行期间一直存在,没有理由丢弃或重新创建另一个实例。
它的最佳作用域:应用作用域
最简单的就是使用单例模式或者静态单例模式。
SqlSession
SqlSession 的实例不是线程安全的,因此是不能被共享的。
所以它的最佳的作用域是:请求或方法作用域。
SqlSession用完及关,否则资源被占用。
列如:每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要。
这里的每一个Mapper,就代表一个具体的业务!
SqlSession可以创建多个mapper!
5、解决字段和属性不一致问题
resultMap (结果映射)
resultMap 元素是 MyBatis 中最重要最强大的元素。
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
作用在解决字段和属性不一致问题:
起因:我们的实体类User属性名与数据库的字段名不一样。
导致查询结果:null
解决方法一:
起别名:as
解决方法二:
使用resultMap解决问题。
什么意思呢?
我们可以通过resultMap去创建User类型,然后通过result 来设置数据库与实体类相对应的字段和属性名。
对应的:
6、日志 6.1 日志工厂
设置(settings)
这是 MyBatis 中极位重要的调整设置,它们会改变 MyBatis 的运行时行为。
STDOUT_LOGGING:标准日志输出
在mybatis核心配置文件中配置日志:
日志打印结果:
6.1 LOG4J
LOG4J概念:
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件。我们也可以控制每一条日志的输出格式。通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
1、导入包。
2、log4j.properties(配置文件属性)与核心配置文件同一个包。
log4j的详细配置(最省心完美配置)_菜鸟先飞-CSDN博客_log4j配置文件
3、配置LOG4J为日志的实现。
4、log4j的使用,直接运行。
LOG4J简单使用
1、在使用LOG4J之前,导入import org.apache.log4j.Logger;包,写入配置文件。
2、日志对象,参数为当前类。
Logger logger = Logger.getLogger(UserDaoTest.class);
3、日志级别。
logger.info("info:进入了testLog4j");logger.debug("debug:进入了testLog4j");logger.error("error:进入了testLog4j");
7、分页 7.1 Limit分页
作用:减少数据的处理量。
语法:
步骤:
1、写接口
2、写Mapper.xml
3、测试
// 分页查询@Testpublic void getUserLimit(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map
7.2 RowBounds分页
通过RowBounds来分页查询
1、接口
2、编写sql
3、测试
// 分页查询@Testpublic void getUserRowBounds(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); RowBounds rowBounds = new RowBounds(0, 2); List
8、注解开发
1、写接口。
2、注册接口在mapper.xml中,实行类注册。
3、测试
@Testpublic void getUser(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List
注解的本质就是:反射机制实现。
底层:动态代理。
什么是动态代理呢?
比如:委托人,维托一件事情给目标对象,然后我们真实对象和代理对象就一起去完成目标对象。
代理对象的作用就是帮真实对象扩展了一些方法。
mybatis执行原理
注解的CRUD
@Param(""):注解
在使用基本类型参数或者String类型参数的时候加上@Param("")。
引用类型不用加。
只有一个基本类型参数的时候不用加@Param(""),但是也建议加上。
我们SQL中用的就是我们这里的@Param("")中设置的属性名。
1、接口
public interface UserMapper { @Select("select * from mybatis.user") List
测试:
我们可以在工具类中设置事务提交为true,这样我们就可以不用手动提交事务了。
public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(true); // 优化后的}
@Testpublic void getUser(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); sqlSession.close();}
注意:我们必须要将接口绑定到我们的核心配置文件中。
9、Lombok
Lombok概念:Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。
使用步骤:
1、在IDEA中加入Lombok插件。
2、导入Lombok的依赖jar包。
3、把注解写到实体类上面。
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
实体类
2022-1-12的jar包
@所有可使用的注解
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
10、测试多对一
多个学生对应一个老师就是多对一。
环境搭建
数据库搭建
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 =utf8insert 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)
1、导入Lombokjar包。
2、创建实体类对应数据库,teacher,student。
@Datapublic class Student { private int id; private String name; // 学生需要关联一个老师 private Teacher teacher;}
3、创建dao层Mapper接口。
4、创建接口对应的核心配置文件。
5、注册配置核心文件,(可以使用recources方法,也可以使用class方法,方法很多,自己选择)。
6、测试。
按照查询嵌套处理
首先:
我的思路,查询学生的所有信息,再根据学生的tid,来查询对应的老师。
写好查询语句,id对应接口中写的方法,resultMap结果映射中配好id和要查询的类型,再写上对应的实体类属性名,和数据库列名。
如何查询到Teacher类型的数据呢?
通过association 设置实体类的属性名和数据库的列名,然后添加要查询的实体类也就是Java类型javaType(这里实体类不就对应数据库列名的了吗),在嵌套一个子查询方法名getTeacherId,
子查询查询的就是teacher的id对应的接口中的方法名称,那么现在子查询不是查询到数据库中teacher的id了吗,最后测试结果。
按照结果嵌套处理
思路:
写好数据库中可以查到学生id,name,老师name的SQL语句。
放到xml映射查询中,通过resultMap 去添加对应的实体类属性名,和数据库的列名,
那么teacher类型不是对应的Teacher吗,那么就直接给它association 设置一个Java类型为Teacher,在通过result对应来找到实体类中的属性名和Teacher中的tname。
注意,这里的sql语句写了别名。
11、一对多 环境搭建
1、导入核心配置文件。
2、创建实体类。
@Datapublic class Teacher { private int id; private String name; private List
3、创捷dao接口。
4、创建Mapper.xml对应dao接口,写好sql语法。
5、在核心配置文件中注册。
6、测试。
按照查询嵌套处理映射小结
1、关联-association 【多对一】。
2、集合-collection【一对多】。
3、javaType & ofType。
javaType :用来指定实体类中属性的类型。
ofType:用来指定映射到List或者集合中的pojo类型,也是泛型中的约束类型。
注意:
写SQL的时候要保证可读性,尽量通俗易懂。
注意一对多和多对一中,属性名和字段名的问题。
12、动态SQL
好处:
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
概念:
什么是动态sql:动态sql就是根据不同的条件生成不同的sql语句。所谓的动态sql,还是sql语句,只是我们可以在sql层面增添一些逻辑代码。动态sql就是在拼接sql语句,我们只需要保证sql的正确性,按照sql的格式,去排列组合就可以了。搭建环境
create table blog(id varchar(50) not null,title varchar(100) not null ,author varchar(30) not null ,create_time datetime not null ,views int(30) not null)engine =innodb default charset = utf8
使用步骤:
1、导入核心配置文件,导入工具类。
2、写实体类。
3、写接口。
4、写Mapper.xml。
5、到核心配置文件中注册。
6、测试。
if
if 的test 做sql判断,author 对应数据库中的列名。
if 的意思是,如果test中的字段不是空的,那么就进行sql语句!
但是:我们sql语句中不能出现where 1 = 1 的情况,如何解决这种情况呢?
使用where标签
trim(where、set)
where 元素只会在子元素返回任何内容的情况下才插入 “WHERe” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
where:
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
set:
trim:覆盖了后缀值设置,并且自定义了前缀值。
...
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
只要满足了第一个条件语句,那么就不会在走剩下的语句了。
sql片段
有时候,我们可能会将一些功能的部分抽取处理,方便复用。
1、使用sql标签抽取公共的部分:
2、在需要使用的地方使用include标签引用即可:
注意:
最好基于单表来定义sql片段。sql片段中不用有where标签。
forEach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
而且foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符。
collection:键
item:值
测试代码
通过xml映射,在测试类里,写好三步骤,和HashMap。
然后创建一个数组,把id取值(1,2,3)存到ids中,最后把ids存到HashMap中,通过查询map,来便利的查到的数据。
ids是foreach标签中的collection。
@Testpublic void test4(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); ArrayList
13、缓存
什么是缓存呢?
缓存就是用户存入的数据,那数据就存放到一个地方,那个地方就是缓存。缓存解决了高并发系统的性能问题。还提升了查询效率。
为什么使用缓存?
目的:减少和数据库的交互次数,减少系统开销,提高系统效率。
什么样的数据库使用缓存?
数据经常查询,且不经常改变的数据,就使用缓存。
缓存还分为两级:
一级缓存
一级缓存是默认开启的。
相当于测试类里面的一个测试结果,从sqlSession中查询结果,最后关闭sqlSession,就是一级缓存,因为数据只在这个测试期间使用,用完就关闭了。
二级缓存
二级缓存也叫全局缓存,因为一级缓存作用域太低了,所以诞生的二级缓存。
只有将会话关闭后,或提交,才会到二级缓存中。
二级缓存也可以看成基于xml配置文件中的namespace 一个名称空间,对应一个二级缓存 ,因为这个缓存存在于,整个xml的使用中。
工作机制:
一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中。如果当前会话关闭了,这个会话对应的一级缓存就没了,但是我们想要的是,会话关闭后,一级缓存中的数据被保存到二级缓存中。新的会话查询信息,就可以从二级缓存中获取内容。不同的mapper查出的数据就会放在自己对应的缓存(map)中。
二级缓存表现形式:
我们使用一级缓存查询两遍同样的数据。那么会查到两遍同样的数据,当我们把二级缓存打开时,我们再进行查询,这时候我们的一级缓存不是被提交了吗,或关闭了,这时候查出来的数据就只有一遍。
1.开启全局缓存
在核心配置文件中设置开启二级缓存:
2.在配置文件中设置二级缓存:
也可以自定义二级缓存
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。