建一个个人网站,asp网站用什么软件,wordpress 登录信息,室内装修设计图片欣赏MyBatis 大家好呀#xff01;我是小笙#xff0c;我中间有1年没有更新文章了#xff0c;主要忙于毕业和就业相关事情#xff0c;接下来#xff0c;我会恢复更新#xff01;我们一起努力吧#xff01; 概述
MyBatis 是一个持久层的框架#xff08;前身是 ibatis#x…MyBatis 大家好呀我是小笙我中间有1年没有更新文章了主要忙于毕业和就业相关事情接下来我会恢复更新我们一起努力吧 概述
MyBatis 是一个持久层的框架前身是 ibatis在 ibatis3.x 的时候更名为 MyBatis
为什么使用 MyBatis 框架
简化以及规范化连接数据库不需要手动连接数据库程序不再是以一种硬编码的形式实现解耦灵活性高
MyBatis 核心框架图 简易实现 MyBatis 底层机制
备注简易实现MyBatis底层机制所用到的表如上述快速入门实现的是简单查询用户数据
实现框架图 SqlSession 类的设计
SqlSession主要是用来连接数据库以及操作数据库
public class SqlSession {/*** 主要用来连接数据库*/private Configuration configuration new Configuration();/*** 主要用来操作数据库*/private ExecutorImpl executor new ExecutorImpl();/*** 直接操作数据库来查询用户数据*/public T T selectOne(String statement, Object parameter) {try {return executor.selectOne(statement, parameter);} catch (SQLException throwables) {throw new RuntimeException();}}/*** 返回mapper的动态代理对象*/public T T getMapper(ClassT clazz) {return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz},new MapperProxy(configuration,this,repo/UserMapper.xml));}
}Configuration 类主要是用来读取配置文件
读取config数据库配置文件获取连接读取mapper接口以及mapper接口对应的xml配置文件信息封装到MapperBean对象中
/*** 配置读取类*/
public class Configuration {// 日志输出private static Logger log Logger.getLogger(com.Altair.myBatis.logs);;// 获取资源加载类private static ClassLoader loader ClassLoader.getSystemClassLoader();/*** 读取配置文件* param configName 配置文件名字* return*/public Connection ReadConfig(String configName) {Connection connection null;try {// 获取 xml 配置文件流InputStream stream loader.getResourceAsStream(configName);// SAXReader 读取 xml 配置文件内容SAXReader read new SAXReader();Document document read.read(stream);// 获取 config 根目节点Element rootElement document.getRootElement();if(Constants.DATABASE_CONFIG.equals(rootElement.getName())){String driver ;String url ;String username ;String password ;for (Object o : rootElement.elements(Constants.DATABASE_PROPERTY)) {Element element (Element) o;String name element.attributeValue(name);String value element.attributeValue(value);if(name null || value null){log.info(异常报错信息:数据库配置参数错误或者不全!);throw new RuntimeException(异常报错信息:数据库配置参数错误或者不全!);}switch (name){case Constants.DATABASE_PARAM.DRIVER:driver value;break;case Constants.DATABASE_PARAM.URL:url value;break;case Constants.DATABASE_PARAM.USERNAME:username value;break;case Constants.DATABASE_PARAM.PASSWORD:password value;break;default: break;}}connection getConnection(driver,url,username,password);}}catch (Exception e){log.info(异常报错信息: e.getMessage());throw new RuntimeException(异常报错信息: e.getMessage());}return connection;}/*** 获取数据库连接*/private Connection getConnection(String driver,String url,String username,String password){if(driver || url || username || password ) {log.info(异常报错信息:数据库配置参数不全!);throw new RuntimeException(异常报错信息:数据库配置参数不全!);}try {Class.forName(driver);return DriverManager.getConnection(url, username, password);}catch (Exception e){log.info(异常报错信息:数据库连接异常!);throw new RuntimeException(异常报错信息:数据库连接异常!);}}/*** 读取Mapper.xml文件生成MapperBean对象* param filePath xml文件路径* return MapperBean对象*/public MapperBean readMapper(String filePath){MapperBean mapperBean new MapperBean();// 获取文件流InputStream stream loader.getResourceAsStream(filePath);// SAXReader 读取 xml 配置文件内容SAXReader saxReader new SAXReader();Document doc null;try {doc saxReader.read(stream);} catch (DocumentException e) {throw new RuntimeException(读取xml配置文件失败!);}// 获取 mapper.xml 根目节点Element root doc.getRootElement();// 对应Mapper接口路径String namespace root.attributeValue(namespace).trim();mapperBean.setInterfacePath(namespace);// 获取迭代器-遍历所有节点Iterator iterator root.elementIterator();ListFunction funs new ArrayList();while(iterator.hasNext()){Element node (Element)iterator.next();Function function new Function();function.setSqlType(node.getName());function.setSql(node.getTextTrim());function.setFuncName(node.attributeValue(id).trim());String parameterType node.attributeValue(parameterType);if(parameterType ! null){Class? aClass null;try {aClass Class.forName(parameterType.trim());function.setParamster(aClass.newInstance());} catch (Exception e) {throw new RuntimeException(传入参数对象异常! e.getMessage());}}String resultType node.attributeValue(resultType);if(resultType ! null){Class? aClass null;try {aClass Class.forName(resultType.trim());function.setResultType(aClass.newInstance());} catch (Exception e) {throw new RuntimeException(返回参数对象异常! e.getMessage());}}funs.add(function);}mapperBean.setFunctions(funs);System.out.println(mapperBean);return mapperBean;}
}MapperBean 类的设计
MapperBean 主要用于封装 Mapper接口以及对应xml文件的信息 /*** 用来连接Mapper接口和Mapper.xml文件*/
Data
public class MapperBean {/*** 接口全路径*/private String interfacePath;/*** 接口的方法信息*/private ListFunction functions;
}/*** 用来记录 Mapper 方法信息*/
Data
public class Function {/*** sql类型*/private String SqlType;/*** sql语句*/private String sql;/*** 方法名*/private String funcName;/*** 参数类型*/private Object paramster;/*** 返回类型*/private Object resultType;
}MapperProxy 代理对象的设计
/*** 简易的代理对象*/
public class MapperProxy implements InvocationHandler {private Configuration configuration null;private SqlSession sqlSession null;private String filePath ;public MapperProxy(Configuration configuration, SqlSession sqlSession, String filePath) {this.configuration configuration;this.sqlSession sqlSession;this.filePath filePath;}/*** 返回代理对象*/Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MapperBean mapperBean configuration.readMapper(this.filePath);//判断是否是xml文件对应的接口if (!method.getDeclaringClass().getName().equals(mapperBean.getInterfacePath())) {return null;}// 取出mapperBean的functionsListFunction functions mapperBean.getFunctions();// 判断当前mapperBean解析对应MappperXML后 , 有方法if (null ! functions 0 ! functions.size()) {for (Function function : functions) {// 当前要执行的方法和function.getFuncName()一样// 说明我们可以从当前遍历的function对象中,取出相应的信息sql, 并执行方法if(method.getName().equals(function.getFuncName())) {if(select.equalsIgnoreCase(function.getSqlType())) {return sqlSession.selectOne(function.getSql(),String.valueOf(args[0]));}}}}return null;}
}测试类
/*** 测试用例*/
public class TestReadMapper {Testpublic void test(){SqlSession sqlSession SessionFactory.openSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.getUserById(53);System.out.println(user: user);}
}快速入门
概述创建、操作 User 用户也就是俗称的 CRUD简单上手了解大致的开发流程
基础环境
引入依赖包 引入jar包形式 mybatis jar包地址 Maven 来构建项目则需将下面的依赖代码置于 pom.xml 文件中 !-- https://mvnrepository.com/artifact/org.mybatis/mybatis --
dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.15/version
/dependency创建数据库表和对象
首先创建一个 User 表
create table user
(id int auto_increment primary key,name varchar(64) not null default ,age int not null default ,email varchar(255) not null default
);User 实体类
Data
public class User {private long id;private int age;private String name;private String email;
}配置连接数据库信息
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttps://mybatis.org/dtd/mybatis-3-config.dtd
configuration!-- 配置日志输出可以输出运行了的MySQL语句 --settingssetting namelogImpl valueSTDOUT_LOGGING//settings!-- 配置别名 --typeAliasestypeAlias aliasUser typecom.Al_tair.entity.User/typeAlias aliasString typejava.lang.String/typeAlias aliasInteger typejava.lang.Integer/typeAlias aliasList typejava.util.List//typeAliases!-- 配置数据库 --environments defaultdevelopment!-- 配置实物管理器 --environment iddevelopmenttransactionManager typeJDBC/!-- 配置数据源 --dataSource typePOOLED!-- 配置驱动 --property namedriver valuecom.mysql.cj.jdbc.Driver/!-- 配置连接数据库 --property nameurl valuexxxxxx/property nameusername valuexxx/property namepassword valuexxxxx//dataSource/environment/environmentsmappersmapper resource./repo/UserMapper.xml/!-- 使用注解的形式 --mapper classcom.Al_tair.mapper.UserAnnotationMapper/mapper/mappers
/configuration配置xml文件方式推荐
UserMapper 接口
public interface UserMapper {/*** 添加用户* param user 用户信息*/public void addUser(User user);/*** 删除用户* param id 用户id*/public void deleteUser(Integer id);/*** 更新用户* param user 用户信息*/public void updateUser(User user);/*** 查询用户* param id 用户id*/public User findUserById(Integer id);/*** 查询用户集合* param ids 用户id*/public ListUser findUsers(Integer[] ids);
}UserMapper 接口对应 UserMapper.xml 文件
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttps://mybatis.org/dtd/mybatis-3-mapper.dtd
!-- namespace: 指定对应的接口 --
mapper namespacecom.Al_tair.mapper.UserMapper!-- id:指定接口对应的方法名 --!-- parameterType:入参数据类型 --insert idaddUser parameterTypeUserinsert into user (name, age, email)VALUES (#{name},#{age},#{email});/insertdelete iddeleteUser parameterTypeIntegerdelete from user where id #{id};/deleteupdate idupdateUser parameterTypeUserupdate user set age #{age},name #{name},email #{email} where id #{id};/updateselect idfindUserById parameterTypeInteger resultTypeUserselect * from user where id #{id};/select
/mapper测试类
public class quickTest {private SqlSession sqlSession;private UserMapper mapper;Beforepublic void init(){sqlSession MyBatisUtils.getSqlSession();mapper sqlSession.getMapper(UserMapper.class);}/*** 添加用户*/Testpublic void test1(){for (int i 0; i 3; i) {User user new User();user.setName(lns i * 2);user.setAge(i 10);user.setEmail(1045645.qq.com);mapper.addUser(user);}if(sqlSession ! null){sqlSession.commit();sqlSession.close();}System.out.println(添加成功...);}/*** 删除用户*/Testpublic void test2(){mapper.deleteUser(44);mapper.deleteUser(45);mapper.deleteUser(46);if(sqlSession ! null){sqlSession.commit();sqlSession.close();}System.out.println(删除成功...);}/*** 修改用户*/Testpublic void test3(){for (int i 0; i 3; i) {User user new User();user.setId(47i);user.setName(zlr i * 2);user.setAge(i 100);user.setEmail(1045645.google.com);mapper.updateUser(user);}if(sqlSession ! null){sqlSession.commit();sqlSession.close();}System.out.println(修改成功...);}/*** 查询一条用户数据*/Testpublic void test4(){User user mapper.findUserById(53);if(sqlSession ! null){sqlSession.close();}System.out.println(查询成功,数据: user);}
}使用注解方式
配置文件需要添加该如下配置
mappers!-- 使用注解的形式 --mapper classcom.Al_tair.mapper.UserAnnotationMapper/mapper
/mappers接口采用注解的形式填入SQL语句
public interface UserAnnotationMapper {/*** 添加用户** param user 用户信息*/Insert(insert into user (name, age, email) VALUES (#{name},#{age},#{email});)public void addUser(User user);/*** 删除用户** param id 用户id*/Delete(delete from user where id #{id};)public void deleteUser(Integer id);/*** 更新用户** param user 用户信息*/Update(update user set age #{age},name #{name},email #{email} where id #{id};)public void updateUser(User user);/*** 查询用户** param id 用户id*/Select(select * from user where id #{id};)public User findUserById(Integer id);/*** 查询用户集合** param ids 用户id*/Select(select * from user where id in #{id};)public ListUser findUsers(Integer[] ids);
}测试方法
public class AnnotationTest {private SqlSession sqlSession;private UserAnnotationMapper mapper;Beforepublic void init(){sqlSession MyBatisUtils.getSqlSession();mapper sqlSession.getMapper(UserAnnotationMapper.class);}/*** 测试查询一条用户数据*/Testpublic void test(){User user mapper.findUserById(53);if(sqlSession ! null){sqlSession.close();}System.out.println(查询成功,数据: user);}
}注解配置方式的总结
// 增删改查操作
Insert(SQL语句)
Delete(SQL语句)
Update(SQL语句)
Select(SQL语句)// id自增长(keyProperty 对应的是对象属性名keyColumn对应的是表的字段名)
Options(useGeneratedKeys true,keyProperty id,keyColumn id)映射器
select 元素的属性
属性描述id在命名空间中唯一的标识符可以被用来引用这条语句。parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的因为 MyBatis 可以通过类型处理器TypeHandler推断出具体传入语句的参数默认值为未设置unset。resultType期望从这条语句中返回结果的类全限定名或别名。 注意如果返回的是集合那应该设置为集合包含的类型而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性如果你对其理解透彻许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。flushCache将其设置为 true 后只要语句被调用都会导致本地缓存和二级缓存被清空默认值false。useCache将其设置为 true 后将会导致本条语句的结果被二级缓存缓存起来默认值对 select 元素为 true。timeout这个设置是在抛出异常之前驱动程序等待数据库返回请求结果的秒数。默认值为未设置unset依赖数据库驱动。fetchSize这是一个给驱动的建议值尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置unset依赖驱动。statementType可选 STATEMENTPREPARED 或 CALLABLE。这会让 MyBatis 分别使用 StatementPreparedStatement 或 CallableStatement默认值PREPARED。resultSetTypeFORWARD_ONLYSCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT等价于 unset 中的一个默认值为 unset 依赖数据库驱动。resultOrdered这个设置仅针对嵌套结果 select 语句如果为 true将会假设包含了嵌套结果集或是分组当返回一个主结果行时就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值false。resultSets这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称多个名称之间以逗号分隔。
insert、update、delete元素的属性
属性描述id在命名空间中唯一的标识符可以被用来引用这条语句。parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的因为 MyBatis 可以通过类型处理器TypeHandler推断出具体传入语句的参数默认值为未设置unset。flushCache将其设置为 true 后只要语句被调用都会导致本地缓存和二级缓存被清空默认值对 insert、update 和 delete 语句true。timeout这个设置是在抛出异常之前驱动程序等待数据库返回请求结果的秒数。默认值为未设置unset依赖数据库驱动。statementType可选 STATEMENTPREPARED 或 CALLABLE。这会让 MyBatis 分别使用 StatementPreparedStatement 或 CallableStatement默认值PREPARED。useGeneratedKeys仅适用于 insert 和 update这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键比如像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段默认值false。keyProperty仅适用于 insert 和 update指定能够唯一识别对象的属性MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值默认值未设置unset。如果生成列不止一个可以用逗号分隔多个属性名称。keyColumn仅适用于 insert 和 update设置生成键值在表中的列名在某些数据库像 PostgreSQL中当主键列不是表中的第一列的时候是必须设置的。如果生成列不止一个可以用逗号分隔多个属性名称。databaseId如果配置了数据库厂商标识databaseIdProviderMyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句如果带和不带的语句都有则不带的会被忽略。
parameterType(输入参数类型) 传入简单数据类型 传入对象数据类型查询时需要有多个筛选条件 注意当传入的参数类是 String 时也可以使用 ${} 来接收参数
!-- 实现 findUserByNameORId --
select idfindUserByNameORId parameterTypeUser resultTypeUserSELECT * FROM userWHERE id#{id} OR name#{name}
/select
!-- 模糊查询需要 ${value} 取值--
select idfindUserByName parameterTypeString resultTypeUserSELECT * FROM userWHERE name LIKE %${value}%
/select注意上述传入参数之所以能够简写是需要配置项扫描对应实体类的路径
typeAliasespackage namecom.Al_tair.entity/
/typeAliases传入和返回 HashMap
!--#{id}、#{age} 传入的参数对应 map 里面 key,如果不传值默认为null
--
select idfindUserByIdAndAge_PrameterHashMap_ReturnHashMap parameterTypemap resultTypemapSELECT id,age FROM userWHERE id #{id} AND age #{age}
/select数据库表的字段名和对象属性名不一致解决方法 查询出来的字段添加别名来匹配对象属性名 通过配置 resutlMap 来映射他们之间的关系 !--表的字段名 user_id、user_name、user_email对象的属性名user_id、username、useremail
--
resultMap typeUser idfindAllUserMapresult columnuser_name propertyusername/result columnuser_email propertyuseremail/
/resultMap
select idfindAllUser resultMapfindAllUserMap SELECT * FROM user
/select动态SQL语句
动态 SQL 常用标签
if
!-- 如果用户的年龄不大于0则输出所有用户 ; 反之用户输出的年龄大于0则按照输入的年龄进行过滤 --
select idfindUserByAge parameterTypeInteger resultTypeUserSELECT * FROM user WHERE 1 1!-- test 里面的 age 是来自传入的参数但是想要取到值传入的参数需要加上注解 param(age) --if testage 0AND age #{age}/if
/selectwhere
!-- 过滤查询用户信息 --
select idfindUserByAgeAndName parameterTypeUser resultTypeUserSELECT * FROM userwhereif test age 0And age #{age}/ifif testname ! null and name ! And name #{name}/if/where
/selectchoose/when/otherwise
!-- 过滤查询用户信息 --
select idfindUserByAgeOrName parameterTypeUser resultTypeUserSELECT * FROM user WHEREchoosewhen testage 0age #{age}/whenotherwisename #{name}/otherwise/choose
/selectforeach
!-- 过滤查询用户信息 --
select idfindUserByIds parameterTypeMap resultTypeUserSELECT * FROM userif testids ! null and ids ! WHERE id INforeach collectionids itemid open( separator, close)#{id}/foreach/if
/selecttrim
替换关键字/定制元素的功能扩展了 where 标签的能力
!-- 过滤查询用户信息 --
select idfindUserByAgeAndName parameterTypeUser resultTypeUserSELECT * FROM user!-- trim 标签能够加前缀 where 或者去掉对于的 AND|OR|XXX 的前缀 --trim prefixWHERE prefixOverridesAND|OR|XXXif test age 0And age #{age}/ifif testname ! null and name ! And name #{name}/if/trim
/selectset
在 update 的 set 中可以保证进入 set 标签的属性被修改而没有进入 set 的保持原来的值
!-- 更新用户信息 --
update idupdateUserInfo parameterTypeMapUPDATE usersetif testage 0age #{age},/ifif testname ! null and name ! name #{name},/ifif testemail ! null and email ! email #{email}/if/setWHERE id #{id}
/update一对一映射
配置Mapper.xml
// 用户类
Setter
Getter
ToString
public class User {private String id;private int age;private String name;private String email;private IdCard idCard;private String cardId;
}// idCard类
Setter
Getter
ToString
public class IdCard {private String id;private String userId;private String idCard;
}第一种方法 !-- 映射返回的结果 --resultMap iduserResultMap typeUser!-- 用id 标记主键会优化性能 --!-- result propertyid columnid/ --id propertyid columnid/result propertyage columnage/result propertyname columnname/result propertyemail columnemail/association propertyidCard javaTypeIdCardresult propertyid columnid/result propertyuserId columnuserId/result propertyidCard columnidCard//association/resultMap!-- 查询用户信息 --select idgetUserById parameterTypeString resultMapuserResultMapSELECT * FROM userLEFT JOIN idCard ON idCard.userId user.idWHERE user.id #{id}/select第二种方式
!-- 映射返回的结果 --
resultMap iduserResultMap2 typeUser!-- 用id 标记主键会优化性能 --id propertyid columnid/result propertyage columnage/result propertyname columnname/result propertyemail columnemail/!-- cardId 为查询出来的 IdCard 表的 id 数据--association propertyidCard columncardId selectcom.Al_tair.mapper.IdCardMapper.getIdCardById/
/resultMap
select idgetUserById2 parameterTypeString resultMapuserResultMap2SELECT * FROM user WHERE user.id #{id}
/select注解的方式
/*** 获得idCard*/
Select(SELECT * FROM idCard WHERE id #{id})
public IdCard findIdCardById(String id);
/*** 查询用户*/
Select(select * from user where id #{id})
Results({Result(id true,property id,column id),Result(property age,column age),Result(property name,column name),Result(property email,column email),Result(property idCard,column cardId,one One(select com.Al_tair.mapper.IdCardMapper.findIdCardById))
})
public User findUser(Integer id);多对一映射
/*** 用户信息*/
Data
public class User {private int id;private int age;private String name;private String email;private IdCard idCard;private int cardId;private ListPet pets;
}
/*** 宠物*/
Data
public class Pet {private int id;private String name;private int userId;
}!-- 查询用户 --
resultMap iduserResultMap3 typeUser!-- 用id 标记主键会优化性能 --id propertyid columnid/result propertyage columnage/result propertyname columnname/result propertyemail columnemail/association propertyidCard columncardId selectcom.Al_tair.mapper.IdCardMapper.getIdCardById/collection propertypets columnid selectcom.Al_tair.mapper.PetMapper.getPetByid/
/resultMap
select idgetUserAndPetById parameterTypeString resultMapuserResultMap3SELECT * FROM user WHERE user.id #{id}
/select
!-- 查询宠物信息 --
select idgetPetByid parameterTypeString resultTypePetSELECT * FROM pet WHERE pet.user_id #{id}
/select缓存
一级缓存
概念一级缓存也是本地缓存
目的通过缓存提高反复查询数据库的数据 测试通过传入相同、不同的用户id查询相同的用户信息进行对比发现如下图 一级缓存失效分析
当SqlSession 会话关闭了一级缓存将会失效当执行 SqlSession.clearCache() 可以清除一级缓存当对查询的对象进行了数据库修改则会导致该对象的缓存失效
二级缓存
二级缓存和一级缓存本质都是为了提高检索效率的技术 配置相关内容
1、配置 cacheEnabled 为true默认为true配置在 mybatis-config.xml 文件中
!-- 全局性关闭或开启所有映射器配置文件中已配置的任何缓存不会关闭一级缓存 --
settingssetting namecacheEnabled valuetrue/
/settings2、二级缓存可能使用到了序列化技术需要在实体类上实现序列化接口Serializable
3、配置在 xxxMapper.xml 文件中
!-- 配置二级缓存 1、eviction 清除缓存的策略默认LRU2、flushInterval 刷新间隔单位是毫秒3、size 引用的数量4、readOnly 只是用来查询可以提高效率
--
cacheevictionFIFOflushInterval60000size512readOnlytrue/测试用例如下
二级缓存类似全局变量使用不同 sqlSession 对象依旧能获取到缓存数据
Test
public void test(){sqlSession MyBatisUtils.getSqlSession();mapper sqlSession.getMapper(UserMapper.class);User user mapper.findUserById(2);if(sqlSession ! null){sqlSession.close();}// 使用不同的 sqlSession 对象sqlSession MyBatisUtils.getSqlSession();mapper sqlSession.getMapper(UserMapper.class);User user3 mapper.findUserById(2);if(sqlSession ! null){sqlSession.close();}
}执行顺序
查询数据的顺序 二级缓存 - 一级缓存 - 数据库
二级缓存和一级缓存不会存在相同的数据因为如果是查询数据库的时候会把数据放到一级缓存里只有当SqlSession会话结束的时候才会将一级缓存的数据转移到二级缓存
EnCache 缓存框架
EhCache 是一个纯Java的进程内缓存框架具有快速、精干等特点是Hibernate中默认CacheProvider
引入依赖 pom.xml
dependencygroupIdnet.sf.ehcache/groupIdartifactIdehcache/artifactIdversion2.10.2/version
/dependency
!-- mybatis 支持 ehcache 缓存 --
dependencygroupIdorg.mybatis.caches/groupIdartifactIdmybatis-ehcache/artifactIdversion1.2.1/version
/dependency
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-simple/artifactIdversion1.7.25/versionscopecompile/scope
/dependency添加 ehcache.xml 配置文件
?xml version1.0 encodingUTF-8?
ehcache xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance!-- 磁盘缓存位置 --diskStore pathjava.io.tmpdir/ehcache /!-- 默认缓存 --defaultCachemaxEntriesLocalHeap10000eternalfalsetimeToIdleSeconds120timeToLiveSeconds120maxEntriesLocalDisk10000000diskExpiryThreadIntervalSeconds120memoryStoreEvictionPolicyLRUpersistence strategylocalTempSwap//defaultCache!-- 自定义缓存 --!--name: 缓存名称maxElementsInMemory缓存最大个数timeToIdleSeconds: 设置对象在失效前的允许闲置时间单位秒(在一直不访问这个对象的前提下这个对象可以在cache中的存活时间)timeToLiveSeconds: 设置对象在失效前允许存活时间单位秒(无论对象访问或是不访问(闲置),这个对象在cache中的最大存活时间)overflowToDisk: 当内存中对象数量达到maxElementsInMemory时Ehcache将会对象写到磁盘中diskSpoolBufferSizeMB: 设置DiskStore磁盘缓存的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区maxElementsOnDisk: 硬盘最大缓存个数memoryStoreEvictionPolicy: 当达到maxElementsInMemory限制时Ehcache将会根据指定的策略去清理内存(默认策略是最近最少使用的 LRU--cache nameUserCachemaxElementsInMemory1000eternalfalsetimeToIdleSeconds1800timeToLiveSeconds276000 overflowToDiskfalsememoryStoreEvictionPolicyLRU/
/ehcache添加在 xxxMapper.xml 配置文件
!-- 启用 Ehcache 缓存 --
cache typeorg.mybatis.caches.ehcache.EhcacheCache/