IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介
IDEA创建项目的操作步骤以及在虚拟机里面创建Scala的项目简单介绍_intellij 创建scala
IDEA项目实践——动态SQL、关系映射、注解开发
文章目录
系列文章目录
1.MyBatis
1.1 MyBatis入门
1.ORM框架
2.MyBatis简介
4. MyBatis的工作流程和核心对象
5. 配置日志:
1.2 MyBatis接口开发(代理开发)【较为重要】
1. 实现步骤:
1.创建Mapper接口
2.修改mapper.xml文件中的namespace,放到mapper文件夹
3. 修改主配置文件中映射文件的路径
4.测试接口开发
2. MyBatis动态代理原理
3. MyBatisX 插件
1.3 MyBatis核心配置
0.核心配置文件概览
常见配置:
1.properties元素
2.typeAliases
3.mappers
4.settings
1.4 MyBatis映射文件
1.映射文件概述
2.模糊查询总结
1.5 MyBatis缓存
1.一级缓存(本地缓存)【重点了解一级缓存】
演示一级缓存的案例,实现步骤:
1. 添加MyBatis的依赖
2.添加MyBatis的核心配置文件
3.创建POJO - 基于Lombok
4.创建Mapper接口
5.创建Mapper映射文件
6.创建MybatisUtil工具类
7.测试一级缓存
2.二级缓存(全局缓存)
总结
当今企业级应用的开发环境中,对象和关系数据是业务实体的两种表现形式。业务实体在内存中表现为对象,在数据库中变现为关系数据。当采用面向对象的方法编写程序时,一旦需要访问数据库,就需要回到关系数据的访问方式,这种转换为开发人员带来了很大的麻烦。 ORM框架是一个对象-关系映射的系统化解决方案,当ORM框架完成转换后,开发人员可以直接取用对象。常用的ORM框架有Hibernate和MyBatis,其作用是将数据库查询的数据封装为实体类对象。
ORM框架将数据库查询到的数据封装为实体类对象,ORM映射流程如上图所示。从图中可以看出,实体类与数据库之间通过ORM框架相互映射,应用程序可以直接获取映射完成的实体类。
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.工作流程
MyBatis的工作流程是MyBatis中重要的知识点,整个MyBatis工作流程分为5个步骤。
编写配置文件与映射文件,其中,配置文件设置数据库连接,映射文件设置与SQL文件相关的操作。
MyBatis通过配置文件和映射文件生成SqlSessionFactory对象,此对象在MyBatis整个生命周期中只存在一份,它负责为每一个连接生成SqlSession对象。
通过SqlSessionFactory对象生成SqlSession对象,SqlSession对象在每次连接中只有一个,它封装了操作数据库的所有方法。
在每一次连接中,通过SqlSession对象操作数据库,SqlSession通过底层的Executor执行器执行对应操作。Executor执行器分为两种,一种是普通执行器,另一种是缓存执行器。
Executor执行器将此次操作封装为MappedStatement对象,在执行SQL语句之前,Executor执行器通过MappedStatement对象将输入的实体对象或基本类型数据映射到SQL语句,在执行SQL语句之后,Executor执行器通过MappedStatement对象将SQL语句执行的结果映射为实体对象或基本类型数据
核心在于将关系型数据映射为MappedStatement对象
2.核心对象
(1)SqlSessionFactory
SqlSessionFactory是MyBatis中的核心类,它采用工厂设计模式构建,负责创建SqlSession对象。构建SqlSessionFactory对象需要使用SqlSessionFactoryBuilder类 调用SqlSessionFactoryBuilder类中的builder()方法即可创建SqlSessionFactory对象 build()方法有多种重载,参数可以选填Reader和InputStream的实现类
构建SqlSessionFactory对象
build方法的参数中需要MyBatis配置文件的输入流,接下来创建输入流。调用Resource类的getResourceAsStream()方法,传入配置文件的绝对路径
获得配置文件流之后,将其作为参数传入SqlSessionFactoryBuilder的build()方法中,调用build()方法,返回值就是SqlSessionFactory对象
使用SqlSessionFactory对象
在SqlSessionFactory类中存在openSession()方法与getConfiguration()方法,其中,openSession()方法可以创建SqlSession对象,也可以在该方法中传入参数来设置创建的SqlSession对象,getConfiguration()方法用于获取SqlSessionFactory的配置。
产生SqlSession对象
SqlSessionFactory类的主要作用是生产SqlSession对象,调用SqlSessionFactory对象的openSession()方法就可以产生SqlSession对象。 通过SqlSessionFactory对象生成的SqlSession对象,在每次连接中只有一个,它负责通过各种方法操作数据库。
(2)SqlSession
使用SqlSession对象
SqlSession对象是MyBatis中的核心类对象,在日常开发中,常用SqlSession对象与数据库进行交互。除此之外,SqlSession对象贯穿于整个数据库访问的过程,一定时间段内没有使用SqlSession对象时,需要及时调用SqlSession对象的close()方法,将其关闭。 SqlSession对象提供了执行SQL,提交事务或回滚事务,使用映射器等方法,在方法中需要指定映射文件中的方法。
方法名称 | 说明 |
---|---|
T selectOne(String var1) | 执行单条记录的查询操作,需传入执行查询的方法,返回映射的对象 |
T selectOne(String var1,Object var2) | 执行单条记录的查询操作,需传入执行查询的方法和参数,返回映射的对象 |
List |
执行多条记录的查询操作,需传入执行查询的方法,返回查询结果的集合 |
List |
执行多条记录的查询操作,需传入执行查询的方法和参数,返回查询结果的集合 |
Map |
执行查询操作,返回一个映射查询结果的Map集合 |
Map |
执行查询操作,需传入查询的方法和参数,返回Map集合 |
int insert(String var1) | 执行插入操作,需传入映射文件中的方法名,返回数据库中受影响的数据行数 |
int insert(String var1,Object var2) | 执行插入操作,需传入映射文件中的方法名和参数对象,返回数据库中受影响的数据行数 |
int update(String var1) | 执行更新操作,需传入映射文件中的方法名,返回数据库中受影响的数据行数 |
int update(String var1,Object var2) | 执行更新操作,需传入映射文件中的方法名和参数对象,返回数据库中受影响的数据行数 |
int delete(String var1) | 执行删除操作,需传入映射文件中的方法名,返回数据库中受影响的数据行数 |
int delete(String var1,Object var2) | 执行删除操作,需传入映射文件中的方法名和参数对象,返回数据库中受影响的数据行数 |
commit() | 提交事务 |
commit(boolean var1) | var1默认为false,参数值为true时表示强制提交 |
rollback() | 回滚 |
rollback(boolean var1) | 强制回滚 |
close() | 关闭SqlSession对象 |
T getMapper(Class |
获取映射器 |
有很多内容,了解即可
导入log4j的依赖
log4j
log4j
1.2.12
在应用的类路径中创建一个名为 log4j.properties
的文件,文件的具体内容如下:
# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
#用到的类
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#打印的格式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#具体的格式指定
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
日志记录器(Logger)的行为是分等级的:
1.分为OFF、FATAL【致命错误】、ERROR、WARN、INFO【普通运行信息】、DEBUG【断点调试】、TRACE【跟踪信息】、ALL或者您定义的级别。2.Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。
3.如果log level设置在某一个级别上,那么比此级别优先级高的log都能打印出来,就拿我们常用的4个等级ERROR、WARN、INFO、DEBUG,如果我们设置在INFO上,那程序中所有DEBUG级别的日志将不会打印。
常用几个等级的说明:
1、DEBUG 指定细粒度信息事件是最有用的应用程序调试,一般使用log.debug()进行跟踪调试。2、INFO 指定能够突出在粗粒度级别的应用程序运行情况的信息的消息,就是输出提示信息。info级别监控系统运行情况,可以帮助程序员有效的了解程序的流转。
3、WARN 指定具有潜在危害的情况,一般很少使用。
4、ERROR 错误事件可能仍然允许应用程序继续运行。就是显示错误信息。比如接口访问超时,用try/catch 捕获异常,发生异常的时候log.error输出错误信息,并不影响程序的运行。
上述配置将使 Log4J 详细打印 org.mybatis.example.BlogMapper【详细的包】
的日志,对于应用的其它部分,只打印错误信息。
为了实现更细粒度的日志输出,你也可以只打印特定语句的日志。以下配置将只打印语句 selectBlog
的日志:
log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE
或者,你也可以打印一组映射器的日志,只需要打开映射器所在的包的日志功能即可:
log4j.logger.org.mybatis.example=TRACE
某些查询可能会返回庞大的结果集。这时,你可能只想查看 SQL 语句,而忽略返回的结果集。为此,SQL 语句将会在 DEBUG 日志级别下记录(JDK 日志则为 FINE)。返回的结果集则会在 TRACE 日志级别下记录(JDK 日志则为 FINER)。因此,只要将日志级别调整为 DEBUG 即可:
log4j.logger.org.mybatis.example=DEBUG
使用和指定语句的参数和返回值相匹配的接口(比如 UserMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。
使用XML文件进行开发,在调用SqlSession进行操作时,需要指定MyBatis映射文件中的方法,这种调用方式过于烦琐。为解决此问题,MyBatis提供了接口开发的方式。
接口开发的目的:
解决原生方式中的硬编码
简化后期执行SQL
需修改的地方:
1.在mapper文件夹下创建XxxMapper接口,并定义相应的抽象方法。
2.在mapper文件夹下创建映射文件XxxMapper.xml,并指定其namespace为对应Mapper接口的绝对路径。
3.在MyBatis主配置文件中,将mapper包下所有的Mapper接口引入
4.在pom.xml中配置resource,指定打包资源,使mapper包中的映射文件可以被打包到classes中【另一种方式:也可以不做如下配置,而是把映射文件,放在resources对应的文件夹中】
src/main/java
**/*.xml
package com.ambow.mapper;
import com.ambow.pojo.User;
import java.util.List;
public interface UserMapper {
public List selectUser();
public List searchUser(String keywords);
public int insertUser(User user);
public int updateUser(User user);
public int deleteUser(int id);
}
insert into tb_user values(null,#{username},#{password},#{gender},#{addr})
update tb_user set username = #{username},password = #{password}, gender = #{gender},addr = #{addr}
where id = #{id}
delete from tb_user where id = #{id}
@Test
public void test() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//获取SqlSessionFactory - 工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// System.out.println(sqlSessionFactory);
//获取SqlSession - 连接对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List list = userMapper.selectUser();
for (User user : list) {
System.out.println(user);
}
}
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
主要功能:
XML 和 接口方法 相互跳转
根据接口方法生成 statement
安装:
MyBatis配置文件中有MyBatis框架的核心配置,负责对MyBatis进行全局管理。它包含许多控制MyBatis功能的重要元素。
第一种方式:
第二种方式:
在resources文件夹里面配置配置文件,就可以就直接访问
对应的jdbc.properties源码如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=root
属性值的引用方式为${属性名},具体代码参考如下:
了解一下即可,可以指定日志
Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:
SLF4J
Apache Commons Logging
Log4j 2
Log4j
JDK logging
MyBatis 内置日志工厂会基于运行时检测信息选择日志委托实现。它会(按上面罗列的顺序)使用第一个查找到的实现。当没有找到这些实现时,将会禁用日志功能。
如果你想选择某种日志实现,你可以通过上面的setting来指定。
映射文件是MyBatis中的重要组成部分,它包含了开发中编写的SQL语句、参数、结果集等。映射文件需要通过MyBatis配置文件中的
< select >元素的常用属性:【作为了解内容,后续开发的时候直接查即可】
通过
写法为:
1、使用“${...}”,语法为“like '${...}'”; -->and sName LIKE '%${sName}%'
2、使用“#{...}”,语法为“like '#{...}'”; -->and sName LIKE "%"#{sName}"%"
3、使用[CONCAT]函数连接参数形式,语法为“like CONCAT('%',#{...},'%')”。-->and sName LIKE concat("%",#{sName},"%")
4、使用
参考网址:
mybatis中LIKE模糊查询的几种写法以及注意点_mybatis 模糊查询_槐月十九的博客-CSDN博客
#{}和${}的区别:
“#{}”表示占位符,在组成SQL的过程中,先将此位置占位,之后将取得的值赋值到此位置,在类型上有严格的限制。【相当于用PreparedStatement,不会有SQL注入风险】
“${}”表示拼接符,在组成SQL的过程中,此符号将取得的值直接拼接到相应位置。【相当于用Statement,拼接SQL,有SQL注入风险】
为了减少重复查询给数据库带来的压力,MyBatis提供了缓存机制,这种机制能够缓存查询的结果,避免重复的查询。
MyBatis提供了两种缓存方式,一种为针对于SqlSession的缓存,此种缓存方式默认开启;另一种为针对于全局的缓存,需要手动开启。一级缓存存在SqlSession对象中,二级缓存横跨全部的SqlSession,对所有的查询都生效。
在没有配置的情况下,MyBatis默认开启一级缓存。在实际开发时,使用同一个SqlSession对象调用同一个Mapper方法,往往只执行一次SQL,这是因为,当开启一级缓存时,第一次查询,MyBatis会将查询结果放在缓存中,当再次使用这个SqlSession进行同一个查询时,如果数据库的数据没有被更改,则直接将缓存中的数据返回,不会再次发送SQL到数据库。
1.用户发送查询请求给MyBatis,MyBatis接收到请求时创建一个SqlSession对象处理本次请求的数据库操作,每个SqlSession对象有对应的执行器,执行器在执行SQL语句时会查询Local Cache中是否存在此查询的缓存,如果不存在,则执行此次查询,并将缓存放到Local Cache中;如果存在,则直接将此次查询的缓存返回。
2.当会话结束,即调用SqlSession的close()方法时,会释放此SqlSession中的所有缓存,并将此SqlSession禁用。如果想要清除缓存中的数据,而不关闭SqlSession对象,可以调用SqlSession的clearCache()方法,此方法会清空该SqlSession一级缓存中的所有内容。除此之外,当SqlSession中执行任何一个DML操作,即增加、删除或更改操作时,都将清空此SqlSession的一级缓存
在MyBatis中,对于两次查询,有以下四个条件来判定它们是否是完全相同的两次查询。 1)传入的statementId是否相同 2)查询时结果集范围是否相同 3)查询的最终SQL语句是否相同 4)传递给Statement的参数是否相同 当这些判断都相同时,认为这两次查询完全相同。
如果想要清除缓存中的数据,而不关闭SqlSession对象,可以调用SqlSession的clearCache()方法,此方法会清空该SqlSession一级缓存中的所有内容。除此之外,当SqlSession中执行任何一个DML操作,即增加、删除或更改操作时,都将清空此SqlSession的一级缓存
8
8
1.8
org.mybatis
mybatis
3.4.6
mysql
mysql-connector-java
5.1.6
org.projectlombok
lombok
1.18.24
junit
junit
4.12
test
src/main/java
**/*.xml
src/main/resources
**/*
核心配置文件,需要读取的jdbc.properties文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=root
package com.ambow.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dog {
private int id;
private String name;
private int age;
}
//DogMapper.java
package com.ambow.dao;
import com.ambow.pojo.Dog;
public interface DogMapper {
Dog selectDog();
}
package com.ambow.util;
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;
public class MyBatisUtil {
//获取SqlSession
public static SqlSession getSqlSesssion(){
//获取SqlSession
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
//获取SqlSessionFactory - 工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// System.out.println(sqlSessionFactory);
//获取SqlSession - 连接对象
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
//关闭SqlSession
public static void closeSqlSession(SqlSession session){
if (session != null) {
session.close();
}
}
}
package com.ambow.test;
import com.ambow.dao.DogMapper;
import com.ambow.pojo.Dog;
import com.ambow.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class CacheTest {
/*
一级缓存:
SqlSession级别的缓存,也就是说,同一个SqlSession共用一个缓存对象
*/
@Test
public void test01(){
//获取SqlSession
SqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();
//第一次查询 - id为1
DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog1 = dogMapper01.selectDog();
System.out.println(dog1);
//第二次查询 - id为1
DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog2 = dogMapper02.selectDog();
System.out.println(dog2);
}
/*
一级缓存:
两个SqlSession对象,不会共用一个缓存对象
*/
@Test
public void test02(){
//获取SqlSession
SqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();
SqlSession sqlSesssion02 = MyBatisUtil.getSqlSesssion();
//第一次查询 - id为1
DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog1 = dogMapper01.selectDog();
System.out.println(dog1);
//第二次查询 - id为1
DogMapper dogMapper02 = sqlSesssion02.getMapper(DogMapper.class);
Dog dog2 = dogMapper02.selectDog();
System.out.println(dog2);
}
/*
一级缓存:
SqlSession调用close()方法,缓存会被释放
*/
@Test
public void test03(){
//获取SqlSession
SqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();
//第一次查询 - id为1
DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog1 = dogMapper01.selectDog();
System.out.println(dog1);
sqlSesssion01.close();
//第二次查询 - id为1
DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog2 = dogMapper02.selectDog();
System.out.println(dog2);
}
/*
一级缓存:
调用SqlSession的clearCache()方法,可以释放缓存
*/
@Test
public void test04(){
//获取SqlSession
SqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();
//第一次查询 - id为1
DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog1 = dogMapper01.selectDog();
System.out.println(dog1);
//清除缓存
sqlSesssion01.clearCache();
//第二次查询 - id为1
DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog2 = dogMapper02.selectDog();
System.out.println(dog2);
}
/*
一级缓存:
当SqlSession中执行任何一个DML操作,即增加、删除或更改操作时,都将清空此SqlSession的一级缓存
*/
@Test
public void test05(){
//获取SqlSession
SqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();
//第一次查询 - id为1
DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog1 = dogMapper01.selectDog();
System.out.println(dog1);
//执行DML操作 - 数据更新
int row = dogMapper01.updateDog();
System.out.println("执行了更新语句");
//第二次查询 - id为1
DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);
Dog dog2 = dogMapper02.selectDog();
System.out.println(dog2);
}
}
MyBatis的二级缓存是Application级别的缓存,与一级缓存的原理类似,不同的是,二级缓存的作用域扩大到了每个命名空间,在同一个命名空间中的所有查询都将被缓存。
MyBatis二级缓存的执行流程:
1.MyBatis中的二级缓存默认关闭,需要手动开启,当开启后,用户发送有关数据库操作的请求会被CacheExecutor拦截。
2.CacheExecutor拦截数据库操作后,到Configuration对象中查看对应命名空间中的缓存,如果发现存在相同查询的缓存,则直接返回该缓存;如果不存在,则进入一级缓存中查找。即先经过二级缓存查找后,再从一级缓存中寻找。
MyBatis在执行到DML语句时,会清空当前命名空间中所有的缓存。此外,MyBatis开启二级缓存后可能会有脏读问题:按照开发规范,每个类都有自己的命名空间,命名空间不允许有针对其他类的更改,但如果在B类的命名空间中对A类做出更改时,B类命名空间中的二级缓存将会被清除,A类中的缓存不会被清除,当A类命名空间中有针对于A类的查询操作时,就会寻找二级缓存中的旧数据并将其返回。
演示案例
演示1:不开启二级缓存,一级缓存无法实现跨SqlSession之间的缓存。
演示2:开启二级缓存,可以实现跨SqlSession的缓存。
使用MyBatis的二级缓存,需要以下几步:
在主配置文件中开启全局二级缓存配置
在映射文件中加入
对应的pojo需要实现序列化
注意:测试二级缓存需要commit提交,如果不提交是不会保存到二级缓存的
演示3:执行DML操作后,二级缓存会清空。
演示4:在不规范开发时,二级缓存会出现脏读情况。
按照开发规范,每个类都有自己的命名空间,命名空间不允许有针对其他类的更改,但如果在B类的命名空间中对A类做出更改时,B类命名空间中的二级缓存将会被清除,A类中的缓存不会被清除,当A类命名空间中有针对于A类的查询操作时,就会寻找二级缓存中的旧数据并将其返回。
面试题:说一说MyBatis的缓存机制?
首先MyBatis设计了二级缓存这样一个机制来提升数据检索效率,避免每一次检索都去查询数据库。
一级缓存是SqlSession级别的缓存,也叫本地缓存。因为每一个用户在执行查询的时候,都需要使用SqlSession来执行,为了避免每一次都去查询数据库,MyBatis把查询出来的数据缓存到SqlSession的本地缓存里面,后续的SQL查询,如果命中缓存的情况下,就可以直接从本地缓存去读取数据。
如果要实现跨SqlSession级别的缓存,那么一级缓存无法做到,因此MyBatis引入了二级缓存的设计。当多个用户查询数据的时候,只要有任何一个SqlSession拿到了数据,就会放到二级缓存里面,其他SqlSession就可以直接从二级缓存里面加载数据。
下面我再来解释一下一二级缓存的实现原理,首先看一级缓存,在SqlSession里面会持有一个Executor,每个Executor里面会有一个LocalCache的对象,当用户发起查询的时候,MyBatis会根据执行语句,在LocalCache里面去查找,如果命中了就只把数据返回,如果没有命中,再去数据库中查找,再写入到LocalCache里面,所以,一级缓存的生命周期是SqlSession.需要注意一点:在多个SqlSession或者分布式环境下,可能会因为一级缓存导致脏读的问题。
而二级缓存的实现原理呢,是在原来的Executor上去做了一个装饰,引入了叫CachingExecutor的装饰器,在进入一级缓存的查询之前,会先通过CachingExecutor进行二级缓存的查询。开启二级缓存之后,会被多个SqlSession共享,因此它是一个全局的缓存,所以它的查询流程就变成了,先去查询二级缓存,再去查询一级缓存,最后再去查数据库。另外,二级缓存相比一级缓存,实现了SqlSession之间的缓存数据的共享,同时缓存粒度可以控制到namespace级别,并且还可以通过Cache接口来实现不同缓存实现类的一个组合,对Cache的可控度也更高了。
注意:
第一版:MyBatisUtil.java
package com.ambow.util;
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;
public class MyBatisUtil {
//获取SqlSession
public static SqlSession getSqlSesssion(){
//获取SqlSession
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
//获取SqlSessionFactory - 工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// System.out.println(sqlSessionFactory);
//获取SqlSession - 连接对象
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
//关闭SqlSession
public static void closeSqlSession(SqlSession session){
if (session != null) {
session.close();
}
}
}
第二版:MyBatisUtil.java
package com.ambow.util;
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;
public class MyBatisUtil {
private static SqlSessionFactoryBuilder builder;
private static SqlSessionFactory sqlSessionFactory;
//静态代码块 - 类加载的时候,只执行一次
static {
//获取SqlSession
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
builder = new SqlSessionFactoryBuilder();
//获取SqlSessionFactory - 工厂对象
sqlSessionFactory = builder.build(inputStream);
}
//获取SqlSession
public static SqlSession getSqlSesssion(){
//获取SqlSession - 连接对象
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
//关闭SqlSession
public static void closeSqlSession(SqlSession session){
if (session != null) {
session.close();
}
}
public static SqlSessionFactoryBuilder getBuilder(){
return builder;
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
第二版才能共用一个SqlSessionFactory,而第一版拿到的是两个。
以上就是今天的内容~
欢迎大家点赞,收藏⭐,转发,
如有问题、建议,请您在评论区留言哦。
最后:转载请注明出处!!!