MyBatis
- 回顾
- Java的应用开发,servlet和Jsp。
- MVC中的model,数据访问使用的是JDBC。
- 取到数据库中的数据,将数据封装到对象中,手动操作。
- 存在的问题:
- 手动输入的时候,会写错
- 代码重复量高
- 存在的问题:
- 取到数据库中的数据,将数据封装到对象中,手动操作。
- 企业级框架
- 从今天开始学习
- 框架相当于模版,将主要的技术功能进行了封装,帮助开发人员更专注于你的业务内容,提高企业项目的开发效率。
- 什么是 MyBatis ?
- MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
- 从 XML 中构建 SqlSessionFactory
- 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。
- 数据库连接信息
- XML 配置文件(configuration XML)中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。
- 配置一个数据配置的属性
-
dbconfig.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/oa username=root password=root
- XML中的配置
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="dbconfig.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/compnay/bean/EmployeeMapper.xml" /> </mappers> </configuration>
-
- MyBatis 提供的全部特性可以利用基于 XML 的映射语言来实现
-
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.company.dao.EmployeeDao"> <select id="selectOne" resultType="com.company.bean.Employee"> select * from Employee where eid = #{id} </select> </mapper>
-
- Java代码演示
-
//获得当前Mybatis总的配置文件路径 String resource = "configuration.xml"; //获得当前配置文件的输入流 InputStream inputStream = Resources.getResourceAsStream(resource); //通过流对象来创建一个了SessionFactory对象,数据库会话工厂 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //通过数据库会话工厂,开启数据库的一次会话 SqlSession sqlSession = sqlSessionFactory.openSession(true); //sqlSession使用sql,然后关闭 //所有的数据库操作,都被分装到了Session当中了,增、删、改、查 Employee obj = sqlSession.selectOne("com.company.dao.EmployeeDao.selectOne",10001); System.out.println(obj.getEid()); System.out.println(obj.geteName()); System.out.println(obj.geteAddr()); System.out.println(obj.geteSex());
-
- 从 SqlSessionFactory 中获取 SqlSession
- 既然有了 SqlSessionFactory ,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如
-
SqlSession sqlSession = sqlSessionFactory.openSession(); Employee obj = sqlSession.selectOne("com.company.dao.EmployeeDao.selectOne",10001);
-
- 一种更直白的方式:
- 创建数据访问的接口
-
SqlSession sqlSession = sqlSessionFactory.openSession(); EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class); Employee employee = employeeDao.selectOne(10002);
- 升级项目,通过sqlSession的getMapper方法得到接口的对象
- 创建接口,创建接口中的方法:
-
public interface EmployeeDao { public List<Employee> selectAll(); }
-
- 在Mapper.xml配置文件中,增加查询所有员工的方法
-
<select id="selectAll" resultType="com.company.bean.Employee"> select * from employee </select>
-
- 测试类中调用
-
EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class); //这个接口调用的方法名称必须和xml中的id指定的名称相同 List<Employee> employees = employeeDao.selectAll();
-
- 创建接口,创建接口中的方法:
- 创建接口中的抽象方法
-
public interface EmployeeDao { public List<Employee> selectAll(); public Employee selectOne(int id); public void addEmp(Employee emp); public void updateEmp(Employee emp); public void deleteEmp(int id); public List<Employee> queryList(String name,char sex); public List<Employee> queryList2(@Param("name") String name,@Param("sex") char sex); public List<Employee> queryList3(Map map); public List<Employee> queryByIf(Employee emp); }
-
- 以下是:insert,update 和 delete 语句的示例:
-
<insert id="addEmp"> insert into employee (ename,ePass,eSex,eAge,eTel,eAddr) values (#{eName},#{ePass},#{eSex},#{eAge},#{eTel},#{eAddr}) </insert> <!-- 注意标签,如果是修改需要使用的标签是update --> <update id="updateEmp"> <!-- 注意,这里使用的字段名称要和数据库一直,使用#取值要和实体类一致 --> update employee set ename = #{eName}, eaddr = #{eAddr} where eid = #{eid} </update> <delete id="deleteEmp"> delete from employee where eid = #{id} </delete>
-
- 增加、修改、删除的Java代码如下:
-
public void add(EmployeeDao employeeDao){ Employee emp = new Employee(); emp.seteName("张三"); emp.seteAddr("海南"); emp.seteAge(20); emp.setePass("123123"); emp.seteTel("0108899876"); employeeDao.addEmp(emp); }
-
public void update(EmployeeDao employeeDao){ Employee emp = new Employee(); emp.setEid(10019); emp.seteName("李四111"); emp.seteAddr("新家坡"); employeeDao.updateEmp(emp); }
-
public void delete(EmployeeDao employeeDao){ employeeDao.deleteEmp(10015); employeeDao.deleteEmp(10016); employeeDao.deleteEmp(10017); }
-
- 多条件查询的XML配置
-
<!-- 多条件查询,String name char sex --> <select id="queryList" resultType="com.company.bean.Employee"> <!-- #{}默认采用预处理方式去处理Sql语句 --> <!-- ${}默认采用 非预处理方式去处理数据 --> select * from employee where ename like '${param1}%' and esex = #{param2} </select> <select id="queryList2" resultType="com.company.bean.Employee"> select * from employee where ename like '${name}%' and esex = #{sex} </select> <!-- 使用Map对象传递 --> <select id="queryList3" resultType="com.company.bean.Employee"> select * from employee where ename like '${name}%' and esex = #{sex} </select>
-
- 多条件查询的Java代码
-
//创建接口对象,这个是session对象,通过动态代理自动代理帮我们创意的 EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class); //List<Employee> list = employeeDao.queryList("李", '男'); //List<Employee> list = employeeDao.queryList2("李", '男');//使用注解的方式给参数起别名称 //使用Map方式 Map map = new HashMap<>(); map.put("name", "李"); map.put("sex", '男'); List<Employee> list = employeeDao.queryList3(map);
-
- 多条件查询,条件不固定XML配置
-
<select id="queryByIf" resultType="com.company.bean.Employee"> select * from employee where <if test="eName!=null"> ename like '${eName}%' </if> </select>
-
- 使用注解方式实现
- Dao类的注解方式
-
public interface EmployeeDao2 { @Select("select * from employee") public List<Employee> selectAll(); @Select("select * from Employee where eid = #{id}") public Employee selectOne(int id); }
-
- 在configuration.xml配置文件中增加对使用注解的接口扫描
-
<mapper class="com.home.dao.EmployeeDao2"/>
-
-
Java类中调用
- 在Java中调用和XML方式一致
- Dao类的注解方式
- 模糊查询之:条件不固定
-
<select id="queryIf" resultType="com.company.bean.Employee"> select * from employee where 1=1 <if test="eName != null"> and ename like '${eName}%' </if> </select>
-
- 动态SQL
- Java接口中的定义:
-
public interface EmployeeDao { public List<Employee> queryIf(Employee emp); public List<Employee> queryChoose(Employee emp); public List<Employee> queryByTrim(Employee emp); public void update(Employee emp); public int deleteByList(List<Integer> list); public int deleteByArray(int[] arrays); }
-
- 多条件的模糊查询
-
<!-- select * from employee where 1=1 and ename like '张%' --> <select id="queryChoose" resultType="com.company.bean.Employee"> select * from employee where 1=1 <choose> <when test="eName != null"> and ename like '${eName}%' </when> <when test="eAddr != null"> and eAddr like '${eAddr}%' </when> <otherwise> order by ename; </otherwise> </choose> </select>
-
- 多条件查询,避免使用where 1=1
-
<!-- 意思是,如果是以and开始,那么就用where来替换and或者or --> <select id="queryByTrim" resultType="com.company.bean.Employee"> select * from employee <trim prefix="where" prefixOverrides="AND|OR"> <if test="eName != null"> and ename like '${eName}%' </if> <if test="eAddr != null"> and eAddr like '${eAddr}%' </if> </trim> </select>
-
- 实现多条件更新
-
<!-- update employee SET eName = ?, eAddr = ? where eid = ? --> <update id="update"> update employee <set> <if test="eName!=null">eName = #{eName},</if> <if test="ePass!=null">ePass = #{ePass},</if> <if test="eAddr!=null">eAddr = #{eAddr}</if> </set> where eid = #{eid} </update>
-
- 集合参数传递
- 实现批量删除操作:集合参数传递
-
<!-- delete from employee where eid in ( ? , ? ) --> <delete id="deleteByList"> delete from employee where eid in <foreach item="eid" collection="list" open="(" separator="," close=")"> #{eid} </foreach> </delete>
-
- Java中的实现
-
List<Integer> list = new ArrayList<>(); list.add(10020); list.add(10021); int i = employeeDao.deleteByList(list);
-
- 实现批量删除操作:集合参数传递
- 数组参数传递
- 实现批量操作:数据参数传递
-
<!-- delete from employee where eid in ( ? , ? ) --> <!-- 注意:这里collection中的参数必须是array,不是arrays --> <delete id="deleteByArray"> delete from employee where eid in <foreach item="item" collection="array" open="(" separator="," close=")"> #{item} </foreach> </delete>
-
- Java中代码实现
-
int[] arrays = {10022,10023}; int i = employeeDao.deleteByArray(arrays);
-
- 实现批量操作:数据参数传递
- ResultMap
- resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来, 并在一些情形下允许你做一些 JDBC 不支持的事情。 实际上,在对复杂语句进行联合映射的时候,它很可能可以代替数千行的同等功能的代码。 ResultMap 的设计思想是,简单的语句不需要明确的结果映射,而复杂一点的语句只需要描述它们的关系就行了。
- Java数据访问接口
-
public interface EmployeeDao { public List<Employee> selectAll(); public List<Employee> selectAll2(); public List<Employee> selectAll3(); public List<Employee> selectAll4(); public Employee selectStep(int id); }
-
-
JavaBean代码
-
public class Employee { private int id; private String name; private String address; }
-
-
映射文件
-
第一种方式
-
<!-- 第一种方式,起别名称,实体类和数据库表字段不一致的情况 --> <select id="selectAll" resultType="com.company.bean.Employee"> select eid as id, ename as name, eaddr as address from employee </select>
-
- 第二种方式
-
<!-- 第二种方式,使用resultMap --> <resultMap type="com.company.bean.Employee" id="resultMap1"> <id column="eid" property="id"/> <result column="ename" property="name"/> <result column="eaddr" property="address"/> </resultMap> <select id="selectAll2" resultMap="resultMap1"> select * from employee </select>
-
- 第三种方式
-
<resultMap type="com.company.bean.Employee" id="resultMap2"> <id column="eid" property="id"/> <result column="ename" property="name"/><!-- column中指定查出来字段的名称 --> <result column="eaddr" property="address"/> <result column="d_id" property="dept.id"/> <result column="d_name" property="dept.name"/> </resultMap> <select id="selectAll3" resultMap="resultMap2"> select e.eid eid, e.ename ename, e.eaddr eaddr,d.did d_id, d.dname d_name from employee e,department d where e.did = d.did </select>
-
- Java代码中增加一个部门属性
-
private Department dept;
-
- 第四种方式,联表查询,使用association
-
<resultMap type="com.company.bean.Employee" id="resultMap3"> <id column="eid" property="id"/> <result column="ename" property="name"/><!-- column中指定查出来字段的名称 --> <result column="eaddr" property="address"/> <association property="dept" javaType="com.home.bean.Department"> <id column="d_id" property="id"/> <result column="d_name" property="name"/> </association> </resultMap> <select id="selectAll4" resultMap="resultMap3"> select e.eid eid, e.ename ename, e.eaddr eaddr,d.did d_id, d.dname d_name from employee e,department d where e.did = d.did </select>
-
-
- ResultMap的属性
- resultMap 元素有很多子元素和一个值得讨论的结构。 下面是 resultMap 元素的概念视图。
- constructor - 用于在实例化类时,注入结果到构造方法中
- idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
- arg - 将被注入到构造方法的一个普通结果
- id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
- result – 注入到字段或 JavaBean 属性的普通结果
- association – 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以指定为一个 resultMap 元素,或者引用一个
- collection – 一个复杂类型的集合
- 嵌套结果映射 – 集合可以指定为一个 resultMap 元素,或者引用一个
- discriminator – 使用结果值来决定使用哪个 resultMap
- case – 基于某些值的结果映射
- 嵌套结果映射 – 一个 case 也是一个映射它本身的结果,因此可以包含很多相 同的元素,或者它可以参照一个外部的 resultMap。
- 分步查询
-
<resultMap type="com.company.bean.Employee" id="resultMap4"> <id column="eid" property="id"/> <result column="ename" property="name"/><!-- column中指定查出来字段的名称 --> <result column="eaddr" property="address"/> <!-- 想要完成分步查询 还要使用association 里面不用再次设定(前提是你的实体类和数据库表字段一一对应) --> <association property="dept" select="com.home.dao.DepartmentDao.findDempartmentById" column="did"> </association> </resultMap> <select id="selectStep" resultMap="resultMap4"> select * from employee where eid = #{id} </select>
-
<mapper namespace="com.company.dao.DepartmentDao"> <select id="findDempartmentById" resultType="com.company.bean.Department"> select did as id,dname as name from Department where did=#{did} </select> </mapper>
-
- 什么是延迟加载
- 需求:如果查询订单并且关联查询用户信息。如果先查询订单信息即可以满足要求,当我们需要查询用户信息时候再查询用户信息。把对用户的信息按照需要去查询就是延迟加载。
- 延迟加载:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
- 配置延迟加载,在config.xml中设置为延迟加载,注意配置顺序
-
<!-- 配置文件的顺序不能变,配置延迟加载 settings 需要在properties节点的下面--> <settings> <!--打开延迟加载的开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!--将积极加载改为消极加载及按需加载 --> </settings>
-
- Java单元测试:
-
Employee employee = employeeDao.selectStep(10008); System.out.println(employee.getName()); String dn = employee.getDept().getName(); System.out.println(dn);
-
- 分步查询log4j日志中展示的内容:
-
[23:29:23:393] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==> Preparing: select * from employee where eid = ? [23:29:23:584] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==> Parameters: 10008(Integer) [23:29:23:875] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - <== Total: 1 李小鹏 [23:29:23:877] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==> Preparing: select did as id,dname as name from Department where did=? [23:29:23:878] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==> Parameters: 1(Integer) [23:29:24:052] [DEBUG] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - <== Total: 1 研发部
-
- 延迟加载的配置
- Mybati默认没有开启延迟加载,需要在总配置文件中setting配置。
- 在MyBatis核心配置文件中配置:
- lazyLoadingEnabled、aggressiveLazyLoading
- 小结
- 使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。
- MyBatis的cache缓存
- 什么是缓存
- 缓存就是计算机的一块存储区域,把数据放入到存储区域中,读取速度快。
- MyBatis的缓存
- MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis3 中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。
- 默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行:
- <cache/>
- 什么是一级缓存,为什么使用一级缓存?
- 每当我们使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话。
- 在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。
- 为了解决这个问题,减少资源浪费,MyBatis会在表示会话的SQLSession对象中建立一个简单的缓存,将每次查询到的结果缓存起来,当下次查询的时候,如果判断现有个完全一样的查询,会直接从缓存中将结果取出来,返回给用户,不需要再进行一次查询数据库了。
- 一级缓存
- 如下图所示,MyBatis会在一次会话的表示:一个SqlSession的对象创建一个本地缓存(LocalCache),对每一次查询,都会尝试根据查询的条件去本地缓存中查找是否存在,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。
- 对于会话(Session)级别的数据缓存,我们称之为一级数据缓存,简称一级缓存。
- MyBatis中的一级缓存是怎样组织的?(即SqlSession中的缓存是怎样组织的?)
- SqlSession对象、Executor对象、Cache对象之间的关系如下图所示:
- PerpetualCache实现原理其实很简单,其内部就是通过一个简单的HashMap<k,v>来实现的,没有其他的任何限制。
- 如下是:PepetualCache的代码实现:
-
public class PerpetualCache implements Cache { private String id; private Map<Object, Object> cache = new HashMap<Object, Object>(); public void putObject(Object key, Object value) { cache.put(key, value); } public Object getObject(Object key) { return cache.get(key); } public Object removeObject(Object key) { return cache.remove(key); } public void clear() { cache.clear(); } }
- 一级缓存的生命周期有多长?
- d.SqlSession中执行了任何一个update操作(update()、delete()、insert()),都会清空PerpetualCache对象的数据,但是该对象可以继续使用;
- c.如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
- b.如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
- a.MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
- SQLSession一级缓存的工作流程
- 结束
- 如果没命中:
- 去数据库中查询数据,得到查询的结果;
- 将key和查询到的结果分别作为key,value对,存储到Cache中;
- 将查询结果返回给用户。
- 如果命中,则直接将缓存结果返回;
- 判断从Cache中根据特定的key值取的数据数据是否为空,即是否命中;
- 对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;
- Cache中Map的key值:CacheKey
- MyBatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询:
- 传入的statementId对于MyBatis而言,你要使用它,必须需要一个statementId,它代表着你将执行什么样的Sql;
- 查询时要求的结果集中的结果范围(结果的范围通过rowBounds.offset和rowBounds.limit表示);
- 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql())
- 传递给java.sql.Statement要设置的参数值
- 综上所述,CacheKey由以下条件决定:statementId +rowBounds +传递给JDBC的SQL +传递给JDBC的参数值
- 也可以这样说:如何确定Cache中的key值?
- 换句话说就是:怎样判断某两次查询是完全相同的查询?
- 现在最核心的问题出现了:怎样来确定一次查询的特征值?
- 我们知道,Cache最核心的实现其实就是一个Map,将本次查询使用的特征值作为key,将查询结果作为value存储到Map中。
- MyBatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询:
- MyBatis的缓存机制整体设计以及二级缓存的工作模式
- MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。
- CachingExecutor是Executor的装饰者,以增强Executor的功能,使其具有缓存查询的功能,这里用到了设计模式中的装饰者模式。
- 要想使某条Select查询支持二级缓存,你需要保证:
- 1.MyBatis支持二级缓存的总开关:全局配置变量参数cacheEnabled=true
- 2.该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效
- 3.该select语句的参数useCache=true
- 4.对象的类必须实现序列化接口
- 一级缓存和二级缓存的使用顺序 :
- 二级缓存 ———> 一级缓存 ———> 数据库
- 二级缓存作用域为 Mapper(Namespace);
- configuration.MappedStatement.Cache;项目启动时会初始化;
- Cache的XML配置
- 所有的这些属性都可以通过缓存元素的属性来修改。
-
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
-
eviction默认的是 LRU。 flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。 size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。 readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false
-
eviction默认的是 LRU。 flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。 size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。 readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false
- 什么是缓存
- Cache使用时的注意事项/避免使用二级缓存
- 注意事项
- 只能在【只有单表操作】的表上使用缓存,不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。
- 在可以保证查询远远大于insert,update,delete操作的情况下使用缓存这一点不需要多说,所有人都应该清楚。记住,这一点需要保证在1的前提下才可以!
- 避免使用二级缓存
- 可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
- 缓存是以namespace为单位的,不同namespace下的操作互不影响。
- insert,update,delete操作会清空所在namespace下的全部缓存。
- 通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。
- 可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
- 注意事项
- 使用MyBatis的二级缓存有三个选择:
- MyBatis自身提供的缓存实现;
- 用户自定义的Cache接口实现;(集成Cache 接口)
- 跟第三方内存缓存库的集成;
- 建议了解nosql数据库redis
觉得有点用记得给我点赞哦!
这篇文章就到这里啦,如果觉得有收获的话,不妨给一个赞喔;文章中涉及的内容肯定是不全面的,欢迎大家评论区留言补充。