1.环境搭建
1.1.pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.boxuegu.javaee</groupId>
<artifactId>mybatis-source-learn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-source-learn</name>
<description>mybatis-source-learn</description>
<properties>
<!-- 统一编译版本 -->
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- mybatis版本 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 数据库连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
1.2.数据库脚本:
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for bxg_employee
-- ----------------------------
DROP TABLE IF EXISTS `bxg_employee`;
CREATE TABLE `bxg_employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`last_name` varchar(255) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of bxg_employee
-- ----------------------------
INSERT INTO `bxg_employee` VALUES ('1', 'zhangsan', '1', '[email protected]');
1.3.mybatis-config.xml:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Cofig 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- mybatis插件机制,这里不讲(用的不多) -->
<!-- <plugins>-->
<!-- <plugin interceptor="com.boxuegu.javaee.mybatissourcelearn.MyIntercepts">-->
<!-- <property name="test" value="testvalue"/>-->
<!-- </plugin>-->
<!-- </plugins>-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="EmployeeMapper.xml"></mapper>
</mappers>
</configuration>
1.4.EmployeeMapper:
//mapper层
public interface EmployeeMapper {
public Employee getEmployeeById(Integer id);
}
1.5.Employee:
public class Employee {
private Integer id;
private String lastName;
private String email;
private String gender;
}
2.测试接口
public class Test {
public static void main(String[] args) {
//1.加载配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
//1.1 获取资源转为InputStream
//mybatis自己实现的资源解析流
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
//2. 获取sqlSessionFactory,建造工厂模式的使用
//通过使用sqlSessionFactory获取SQL会话
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
//3. 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//谈过xml文件直接执行sql语句
//Employee employee = sqlSession.selectOne("com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper.getEmployeeById", 1);
//alt+shift+L introduce local variables;
Thread thread = new Thread(() -> System.out.println("test"));
//4. 获取mapper接口实现
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
System.out.println("mapper::::" + mapper.getClass());
//5. 执行sql语句
Employee employee = mapper.getEmployeeById(1);
System.out.println(employee);
} finally {
sqlSession.close();
}
}
}
3.获取resource转为InputStream
3.1.定义一个配置文件为资源:
//1.加载配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
//mybatis自己实现的资源解析流
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
3.2.getResourceAsStream,Ctrl+Enter进去:
/**
* Returns a resource on the classpath as a Stream object
* 以流对象的形式返回类路径上的资源
*
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static InputStream getResourceAsStream(String resource) throws IOException {
return getResourceAsStream(null, resource);
}
注释说的很明显,以流对象的形式返回类路径上的资源,这个路径可以是相对路径,绝对路径,比如说文件上传就是绝对路径,参数里面的null是ClassLoader类型,这里没有加上,待会会加上类加载器;继续看,查看它return的方法,Ctrl+Enter
//大多数方法都是委托给ClassLoaderWrapper,再去做真正的事
private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
/**
* Returns a resource on the classpath as a Stream object
* 以流对象的形式返回类路径上的资源
*
* @param loader The classloader used to fetch the resource
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
if (in == null) {
throw new IOException("Could not find resource " + resource);
}
return in;
}
/**
* Get a resource from the classpath, starting with a specific class loader
* 从类路径获取资源,从特定的类装入器开始
*
* @param resource - the resource to find
* @param classLoader - the first class loader to try
* @return the stream or null
*/
public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
return getResourceAsStream(resource, getClassLoaders(classLoader));
}
/**
* 用5个类加载器一个个查找资源,只要其中任何一个找到,就返回
* Try to get a resource from a group of classloaders
*
* @param resource - the resource to get
* @param classLoader - the classloaders to examine
* @return the resource or null
*/
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {
// try to find the resource as passed
InputStream returnValue = cl.getResourceAsStream(resource);
// now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
/**
* Returns an input stream for reading the specified resource.
* 返回读取指定资源的输入流。
* <p> The search order is described in the documentation for {@link
* #getResource(String)}. </p>
*
* @param name
* The resource name
*
* @return An input stream for reading the resource, or <tt>null</tt>
* if the resource could not be found
*
* @since 1.1
*/
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}
3.3.这里就是使用到了类加载器,
使用类加载器去加载资源,这里给一个外连接,可以细看,理论通用的.
[https://www.cnblogs.com/softidea/p/4251433.html]:
总的来说就是URL对象调用openStream()方法可以返回一个输入流,该输入流指向URL对象所包含的资源.
好,到这里资源就加载了核心配置文件并返回给inputStream.
4.构建SqlSessionFactory
//2. 获取sqlSessionFactory,建造工厂模式的使用
//通过使用sqlSessionFactory获取SQL会话
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
4.1.这个SqlSessionFactoryBuilder就是一个普通的类,进去:
public class SqlSessionFactoryBuilder {
//SqlSessionFactoryBuilder有9个build()方法
它有9个构造方法,我们只看是用到了哪一个
//以下3个方法都是调用下面第8种方法
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
另外两个对象是空的,先不管,
/**
* 第8种方法和第4种方法差不多,Reader换成了InputStream
*
* @param inputStream
* @param environment
* @param properties
* @return
*/
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//建造者模式
//专门处理配置文件的模式
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
4.2.这里使用了建造者模式XMLConfigBuilder专门处理配置文件,
//inputstream系列的构造函数
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
//得到XPathParser实例之后,就调用另一个使用XPathParser作为配置来源的重载构造函数了
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
这里面有有一个XMLMapperEntityResolver(),
public class XMLMapperEntityResolver implements EntityResolver {
// <?xml version="1.0" encoding="UTF-8" ?>
// <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
// 常量定义
//dtd文件就是xml的校验文件,或者是规范文件
private static final String IBATIS_CONFIG_SYSTEM = "ibatis-3-config.dtd";
private static final String IBATIS_MAPPER_SYSTEM = "ibatis-3-mapper.dtd";
private static final String MYBATIS_CONFIG_SYSTEM = "mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_SYSTEM = "mybatis-3-mapper.dtd";
private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";
4.3.dtd文件主要用于xml文件的校验工作,
进入this(new XPathParser(方法
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
/**
* new XPathParser(reader, true, props, new XMLMapperEntityResolver())
* 的参数含义分别是Reader,是否进行DTD 校验,属性配置,XML实体节点解析器。
* <p>
* entityResolver 类似于spring的XML标签解析器,
* 有默认的解析器,也有自定义的比如tx,dubbo等,在这里mybatis硬编码为了XMLMapperEntityResolver。
*
* @param inputStream
* @param validation
* @param variables
* @param entityResolver
*/
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(inputStream));
}
4.4.构造函数赋值
commonConstructor(validation, variables, entityResolver);
/**
* 普通构造函数,除了把参数都设置到实例变量里面去以外,还初始化了XPath
* 设置字段,创建xpath
* @param validation
* @param variables
* @param entityResolver
*/
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
//解析xmlPath的工厂模式,定义变量
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
4.5.resource转为dom树.
/**
* 创建dom
* 主要是根据mybatis自身需要创建一个文档解析器,然后调用parse将输入input source解析为DOM XML文档并返回。
*
* @param inputSource
* @return
*/
private Document createDocument(InputSource inputSource) {
// important: this must only be called AFTER common constructor
try {
//这个是DOM解析方式
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(validation);
//设置由本工厂创建的解析器是否支持XML命名空间
factory.setNamespaceAware(false);
//忽略注释
factory.setIgnoringComments(true);
//忽略空白
factory.setIgnoringElementContentWhitespace(false);
//设置是否将CDATA节点转换为Text节点
factory.setCoalescing(false);
//设置是否展开实体引用节点,这里应该是sql片段引用的关键
factory.setExpandEntityReferences(true);
DocumentBuilder builder = factory.newDocumentBuilder();
//设置解析mybatis xml文档节点的解析器,也就是上面的XMLMapperEntityResolver
//需要注意的就是定义了EntityResolver(XMLMapperEntityResolver),这样不用联网去获取DTD,
//将DTD放在org\apache\ibatis\builder\xml\mybatis-3-config.dtd,来达到验证xml合法性的目的
builder.setEntityResolver(entityResolver);
builder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
}
});
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
4.6.使用了Configuration对象封装dom树的全部节点信息.
返回Document的DOM树,再通过将DOM树转换成XML配置构建器,将XML配置构建器解析成Configuration,其实到了这里就校验了配置文件的合法性,并最终解析配置文件的节点数据交给Configuration对象,
//建造者模式
//专门处理配置文件的模式
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
/**
* 解析配置
*
* @return
*/
public Configuration parse() {
//首先判断有没有解析过配置文件,只有没有解析过才允许解析。如果已经解析过了,报错
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//根节点是configuration mybatis配置文件解析的主流程
//其中调用了parser.evalNode(“/configuration”)返回根节点的org.apache.ibatis.parsing.XNode表示,
// XNode里面主要把关键的节点属性和占位符变量结构化出来
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
返回的是Configuration对象,后面SqlSessionFactory也会用到它:
/**
* 最后一个build方法使用了一个Configuration作为参数,并返回DefaultSqlSessionFactory
*
* @param config
* @return
*/
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
这里就回到了那默认的9个构造方法,这里做了什么,进去看看,果然是默认,他自己实现了SqlSessionFactory这个接口
return new DefaultSqlSessionFactory(config);
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
好,到现在SqlSessionFactory创建完毕.那么 SqlSessionFactory里面有什么呢?就是SqlSession,
5.获取SqlSession
//3. 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
public interface SqlSessionFactory {
//8个方法可以用来创建SqlSession实例
SqlSession openSession();
//最终都会调用2种方法:openSessionFromDataSource,openSessionFromConnection
//以下6个方法都会调用openSessionFromDataSource
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
这个方法做了什么?
// ExecutorType 执行类型,TransactionIsolationLevel 事务级别,autoCommit 是否自动提交
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
public ExecutorType getDefaultExecutorType() {
return defaultExecutorType;
}
//默认为简单执行器 SIMPLE 就是普通的执行器;
// REUSE 执行器会重用预处理语句(prepared statements);
// BATCH 执行器将重用语句并执行批量更新。
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
5.1.使用的是默认执行器,
openSessionFromDataSource()
/**
* @param execType
* @param level
* @param autoCommit 是否自动提交事务 事务管理模式分为两种,自动提交和手工提交
* @return
*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//通过事务工厂来产生一个事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//生成一个执行器(事务包含在执行器里)
final Executor executor = configuration.newExecutor(tx, execType);
//然后产生一个DefaultSqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
//如果打开事务出错,则关闭它
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
//最后清空错误上下文
ErrorContext.instance().reset();
}
}
5.2.最终返回的是SqlSession
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
到了这里,SqlSession已经出来了.
6.获取mapper接口
//4. 获取mapper接口实现
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
System.out.println("mapper::::" + mapper.getClass());
/**
* 得到映射器,这个巧妙的使用了泛型,使得类型安全
* 到了MyBatis 3,还可以用注解,这样xml都不用写了
* Retrieves a mapper.
* @param <T> the mapper type
* @param type Mapper interface class
* @return a mapper bound to this SqlSession
*/
<T> T getMapper(Class<T> type);
6.1返回了泛型,就是接口自己本身
public interface EmployeeMapper {
public Employee getEmployeeById(Integer id);
}
7.调用接口的方法
//5. 执行sql语句
Employee employee = mapper.getEmployeeById(1);
System.out.println(employee);
7.1.mapper找xml文件的sql
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper">
<select id="getEmployeeById" resultType="com.boxuegu.javaee.mybatissourcelearn.dto.Employee">
select id,last_name lastname,gender, email from bxg_employee where id=#{id}
</select>
</mapper>
7.2.返回result:
这里一个简单的mybatis执行流程就完成了.
mapper::::class com.sun.proxy.$Proxy0
Employee{id=1, lastName='zhangsan', email='[email protected]', gender='1'}
8.一级缓存和二级缓存
8.1.它们之间的区别
一级缓存:一级缓存是SqlSession级别,属于单个会话级别的,默认开启,第一次是查询数据库,第二次从缓存中找数据,怎么判断两次会话是否相同?
传入的statementId,查询时要求的结果集中的结果范围,传递给java.sql.Statement要设置的参数值.
二级缓存(全局缓存),
属于SqlSessionFactory级别,mybatis是默认不开启的,需要手动开启,
<!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
<setting name="cacheEnabled" value="true" />
实现二级缓存的pojo必须序列化(实现Serializable接口),实现序列化的数据有多种介质可以存储,不是单独的内存.
开启二级缓存效果:
<1> 映射语句文件中的所有select语句将会被缓存
<2> 映射语句文件中的所有insert、update和delete语句会刷新缓存。
<3> 缓存会使用默认的Least Recently Used(LRU,最近最少使用的)算法来收回。
<4> 根据时间表,比如No Flush Interval,(CNFI没有刷新间隔),缓存不会以任何时间顺序来刷新。
<5> 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用
<6> 缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全的被调用者修改,不 干扰其他调用者或线程所做的潜在修改。
mybatis-config.xml配置,一定要注意最好写在的下面.不然会报错
8.2.二级缓存实现
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Cofig 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 二级缓存实现 -->
<settings>
<setting name="cacheEnabled" value="true"/> <!-- 全局映射器启用缓存 -->
<setting name="useGeneratedKeys" value="true"/> <!-- 允许 JDBC 支持自动生成主键 -->
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="EmployeeMapper.xml"></mapper>
</mappers>
</configuration>
EmployeeMapper.xml配置,数据库有4条数据,期望查询3条集合,但只显示一条sql,证明只查询了一次数据库,每一条查询结束就关闭session会话:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper">
<!--开启本mapper的namespace下的二级缓存-->
<!--
eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。
(1) LRU,最近最少使用的,一处最长时间不用的对象
(2) FIFO,先进先出,按对象进入缓存的顺序来移除他们
(3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
(4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
移除最长时间不用的对形象
flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当
SQL被执行的时候才会去刷新缓存。
size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
这里配置的是1024个对象
readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有
办法修改缓存,他的默认值是false,不允许我们修改
-->
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
<select id="getEmployeeById" resultType="com.boxuegu.javaee.mybatissourcelearn.dto.Employee">
select id,last_name lastname,gender, email from bxg_employee where id=#{id}
</select>
<select id="getEmployeeList" resultType="com.boxuegu.javaee.mybatissourcelearn.dto.Employee">
select id,last_name lastname,gender, email from bxg_employee
</select>
</mapper>
示例:
package com.boxuegu.javaee.mybatissourcelearn;
import com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper;
import com.boxuegu.javaee.mybatissourcelearn.dto.Employee;
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;
import java.util.List;
/**
* @Description
* @Author MissYu
* @Date 2020/6/18 22:22
* @Classname test2
*/
public class test2 {
public static void main(String[] args) {
//1.加载配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
//mybatis自己实现的资源解析流
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
//2. 获取sqlSessionFactory,建造工厂模式的使用
//通过使用sqlSessionFactory获取SQL会话
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
//3. 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//4. 获取mapper接口实现
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//5. 执行sql语句
List<Employee> employeeList = mapper.getEmployeeList();
System.err.println("第一次執行: :" + employeeList);
//每次都关闭sqlsession,避免让mybatis以为是一级缓存.
sqlSession.commit();
List<Employee> employeeList2 = mapper.getEmployeeList();
System.err.println("第二次執行: :" + employeeList2);
//每次都关闭sqlsession,避免让mybatis以为是一级缓存.
sqlSession.commit();
List<Employee> employeeList3 = mapper.getEmployeeList();
System.err.println("第三次執行: :" + employeeList3);
//每次都关闭sqlsession,避免让mybatis以为是一级缓存.
sqlSession.commit();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
sqlSession.close();
}
}
}
结果:
下面三个结果集,只显示了一次sql,这句sql只出现了1次,这样就已经达到了我们的效果了.
Preparing: select id,last_name lastname,gender, email from bxg_employee
[22:57:59:968] [DEBUG] - org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:73) - Cache Hit Ratio [com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper]: 0.0 [22:58:00:223] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:142) - ==> Preparing: select id,last_name lastname,gender, email from bxg_employee [22:58:00:261] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:142) - ==> Parameters: [22:58:00:279] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:142) - <== Total: 4 [22:58:00:280] [DEBUG] - org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:73) - Cache Hit Ratio [com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper]: 0.5 [22:58:00:281] [DEBUG] - org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:73) - Cache Hit Ratio [com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper]: 0.6666666666666666 第一次執行: :[Employee{id=1, lastName='zhangsan', email='[email protected]', gender='1'}, Employee{id=2, lastName='杜蕾斯', email='fasdfsd@qq,com', gender='4'}, Employee{id=3, lastName='馬克龍', email='[email protected]', gender='0'}, Employee{id=4, lastName='我是誰', email='[email protected]', gender='8'}] 第二次執行: :[Employee{id=1, lastName='zhangsan', email='[email protected]', gender='1'}, Employee{id=2, lastName='杜蕾斯', email='fasdfsd@qq,com', gender='4'}, Employee{id=3, lastName='馬克龍', email='[email protected]', gender='0'}, Employee{id=4, lastName='我是誰', email='[email protected]', gender='8'}] 第三次執行: :[Employee{id=1, lastName='zhangsan', email='[email protected]', gender='1'}, Employee{id=2, lastName='杜蕾斯', email='fasdfsd@qq,com', gender='4'}, Employee{id=3, lastName='馬克龍', email='[email protected]', gender='0'}, Employee{id=4, lastName='我是誰', email='[email protected]', gender='8'}]
另外关于一级缓存和二级缓存共存,你开启了二级,如果一级缓存有数据就拿一级缓存的,没有拿二级缓存的.至此.mybatis全部结束.