详解Mybatis

mybatis

1. mybatis的介绍

1.mybati是什么
是一个基于orm思想的优秀的持久层数据库框架

他就是ibatis的衍生

#### 2. mybatis能做什么

1. 框架学习简单,涉及的依赖和配置很少
2. mybatis相对于其他持久层框架编写sql更加灵活
3. mybatis支持动态sql,可以根据业务需求动态生成sql
4. mybatis还支持注解添加sql语句,添加语句更简单
5. mybatis不需要你做事务相关和资源的释放
6. mybatis有很强大的resultMap结果集映射标签,可以更简单的实现多表查询
7. mybatis支持跨平台命名规范    user_name as username
8. mybatis友好支持第三方插件,例如做分页
9. mybatis支持逆向工程,可以完成绝大部分的sql语句,实现查询;
10. mybatis支持来发人员任意修改sql语句,而hibernate只提供方法,不允许修改。
11. 官方文档齐全

#### 3. 什么是orm思想

1. 对象关系映射(Object Relational Mapping,简称ORM),将实体类通过元数据映射数据库中的具体表和行,开发人员只用面向对象思想进行编程就可。对象关系映射是通过使用描述对象和数据库之间映射的[元数据]将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示着额外的执行开销;

### 4.基于org思想的持久层框架的异同点

相同点:

1. 提供面向对象的数据库操作方法  save()  update()
2. 帮助我们写sql语句,数据库方法-----orm映射---数据库crud

   ##### hibernate:全自动orm持久层框架

   提供一套完整的数据库操作方法

   提供所有方法对应的sql语句只需要学习有哪些方法,不用管理sql的执行

   ##### mybatis:半自动持久层框架

   提供完整的数据库操作方法

   没有提供sql语句的实现

   直接暴露sql 对应的mapper文件,可以随便修改,因此更加的灵活

2. mybatis的基本使用一个

步骤一:导入依赖

mybatis 3.4.5

mysql

cglib足够!!!myBatista的优点之一,只需要导入一个jar就可实现mybatis

步骤二:编写mybatis核心配置文件
<?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="db.properties"/>
<settings>
<!--驼峰命名与数据库字段匹配-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--<setting name="useGeneratedKeys" value="true"/>-->
<!--此处有很多核心的全局数据库设置-->
</settings>
<!--起别名-->
<typeAliases>
<!--按照全类路径名起别名-->
<!--<typeAlias type="com.it.mapper.BMapper" alias="b"/>-->
<!--按照包起别名   默认包下的类名首字母小写-->
<package name="com.it.pojo"/>
</typeAliases>

<!--数据库环境-->
<environments default="dev">
<!--开发   测试 。。。-->
<environment id="dev">
   <!--事务管理    -->
   <transactionManager type="jdbc"></transactionManager>
   <!--连接池-->
   <dataSource type="POOLED">
       <!--具体数据库四个属性-->
       <property name="driver" value="${jdbc.driver}"/>
       <property name="url" value="${jdbc.url}"/>
       <property name="username" value="${jdbc.username}"/>
       <property name="password" value="${jdbc.password}"/>
   </dataSource>
</environment>
</environments>
<!--映射的mapper文件-->
<mappers>
<!--按照目录引入-->
<!--<mapper resource="com/it/mapper.UserMapper.xml"/>-->
<!--按照包名引入mapper文件-->
<package name="com.it.mapper"/>
</mappers>
</configuration>
步骤三:编写mapper配置文件
<?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.it.mapper.AMapper">//namespace mapper的全类路径名
	<!--执行sql语句标签 id必须要和接口中的方法名一样-->
<insert id="insertA" keyColumn="a_id" keyProperty="aId"         useGeneratedKeys="true" >
	<!--具体的sql语句-->
  insert into a(a_name) values(#{aName})
</insert>
<select id="selectById" resultType="a">
select * from a where a_id=#{aid}
</select>
</mapper>
步骤四:编写编写测试
@Test
public void testa() throws IOException {
  //获取核心配置文件
  InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
  /**
         * 获取SqlsessionfactoryBuilder  此对象只用一次,因此放在局部就可以 
         * sqlsession只用一个,因此只用创建一个就可以了
   */
  SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
  //获取sqlsessionfactory
  SqlSessionFactory factory = factoryBuilder.build(resourceAsStream);
//      //创建sqlsession  他是具体的执行对象
  SqlSession sqlSession = factory.openSession();
  
  //crud。。。
  //ibatis和mybatis的使用区别,ibatis需要类,,命名空间可以随便写,就是为了区分而存在,并在执行语句中传入statment字符串,以及对象
  
  //mybatis需要接口,接口名要和mapper文件的标签里面的id名称要相同,
  
  //提交  因为默认开启事务
  sqlSession.commit();
  sqlSession.close();

}

步骤五:在pom文件引入src下的xml配置文件
<resources>
<resource>
  <directory>src/main/java</directory>
  <includes>
    <include>**/*.xml</include>
  </includes>
</resource>
</resources>
提取工具类方法
public class MybatisUtils {
//    工厂
 private static SqlSessionFactory factory =null;
 static {
     //输入流
     InputStream resourceAsStream = null;
     try {
//            读取配置文件
         resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
     } catch (IOException e) {
         e.printStackTrace();
     }
//        只用一次的创建对象
     SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
     factory = factoryBuilder.build(resourceAsStream);

 }
//    获取方法
 public static SqlSession openSqlSession(){

     SqlSession sqlSession = factory.openSession();

     return sqlSession;
 }
 //mybaits默认开启事务管理,因此需要提交和关闭
 public static  void commitAndClose(SqlSession sqlSession){
     sqlSession.commit();
     sqlSession.close();
 }
}
mybatis核心配置讲解
properties:

用来申明变量和引入外部配置文件的,例如数据库配置文件db.properties文件

//也可以申明内部property标签,如果内部属性名和外部相同,内部会覆盖掉外部配置

settings:(核心全局设置标签)

开启后台sql语句的输出

name就是属性 value就是对应的配置

//开启驼峰命名自动映射

默认不开启

指定应如何映射列与属性,

NONE|不映射

PARTIAL|没有嵌套的映射

FULL 默认PARTIAL:映射任意复杂的嵌套映射

使用日志

value:sef4j|log4j|conmmons-loging…

STDOUT_LOGGING输出sql在控制台

当所有列都是空,会返回一个null,当开启后,会返回一个空的对象

默认false

typeAliases:别名

typeAlias:按照全部类路径名 给类起别名

package按照包名给类起别名,就是包下的所有类默认类名首字母小写的形式别名

内置气的别名,基本类型首字母小写。。。

environments(环境配置)

environment(环境变量)

transactionManager(事务管理)

dataSource(数据源)

Mapper映射mapper.xml文件

可以根据目录映射

也可以根据包名映射

允许在插入时获取插入记录的主键信息

useGenaretedKeys 默认关闭

mapper文件配置

cache:对给定的命名空间缓存设置

cache-ref:对其他命名空间缓存设置

resultMap:复杂结果集的映射

sql:sql片段,为了简化大量的相同的代码块的重写冗余

insert…crud标签

crud里的属性

insert:

keyProperty =“属性id”

keyColumn =“列id”

useGenerateKeys=“true” 生成主键相关,在插入记录时候获取主键信息

timeOut=“20” statement语句的执行超时时间单位s

update:

flusheCahche=“true”

statementType=“PREPARED”…statment

delete:

3. mybatis的传参问题

  1. $和#的区别

$用来字符串的拼接#用来占位

写#就相当于要用statementType=“PREPARED”

例如:

<select id="queryAccountByCommonsParam"  resultType="ergouzi">
		           select * from account where ${columnName} = #{value}
		    </select>
  1. 传入单个参数时候

#{} ${} 里面的key可以任意写

  1. 多个参数时候时

默认一个方法传入多个参数时候无法通过${} #{} 获取到值

  1. 可以传入对象

    在接口方法中类型是一个对象

    $ 和 # 的引入必须和对象数据姓名一致

  2. map的方式

    方法传入map sql语句中引入map的key就可以

    引入值必须是key

  3. 注解方式@Param(“具体名字”),¥{} #{}中名字必须要和@Param里面的一样

4. mybatis的主键生成策略

主键:

为了区分一条记录不重复的列

自然主键:本来有的属性,属性刚好符合唯一特性,我们可以看作逐渐(不推荐使用)

自定义主键:专门设置的一列,没有其他描述的含义。

主键一旦设定,不能修改,只能删除,新添加的主键不能沿用(无法在插入的对象中找到主键)。

数据类型(int,bigint,long)主键自动增长,auto_increment;

优点:自动增长,不需要维护。

字符串类型:

没有自动增长的属性,

uuid永远不重复,理论上无穷,需要自己维护

1. 数字类型的主键获取
<insert id="insertInfo" parameterType="Info">    
 insert into  info (i_info,a_id) values (#{iInfo},#{aId})
</insert>
@Test
 public void test6(){
     SqlSession sqlSession = MybatisUtils.openSqlSession();
     InfoMapper mapper = sqlSession.getMapper(InfoMapper.class);
     Info info = new Info();
     info.setaId(1);
     info.setiInfo("良好品质,请放心购买");

     int i = mapper.insertInfo(info);
     System.out.println("i = " + i);
     System.out.println("info = " + info);


     MybatisUtils.commitAndClose(sqlSession);
 }

resoult:
info = Info{iId=0, iInfo='良好品质,请放心购买', aId=1}
可以发现iId为空
获取主键:
修改:
<insert id="insertInfo" parameterType="Info" keyColumn="i_id" keyProperty="iId" useGeneratedKeys="true">
     insert into  info (i_info,a_id) values (#{iInfo},#{aId})
 </insert>
//keyColumn为数据库主键名  keyProperty为实体类属性
//useGenerateKeys="true" 代表获取主键值  默认false
执行测试:
result:
info = Info{iId=8, iInfo='良好品质,请放心购买', aId=1}
iId获取到了
2. 字符串类型的主键获取
<insert id="add" parameterType="User" >
 //插入primary   keyColumn:主键名字    keyProperty:主键属性
 //order :before在inser语句执行前后后执行   
     <selectKey keyColumn="i_id" keyProperty="uId" order="BEFORE" resultType="string">
         select uuid();//生成唯一串
     </selectKey>
     insert into  user (u_id,uname,age) values (#{uId},#{uName},#{age})
 </insert>

@Test
 public void test7(){
     SqlSession sqlSession = MybatisUtils.openSqlSession();
     UserMapper mapper = sqlSession.getMapper(UserMapper.class);
     User user = new User();
     user.setAge(12);
     user.setuName("珍君");
     int add = mapper.add(user);
     System.out.println("add = " + add);
     System.out.println("user = " + user);
     MybatisUtils.commitAndClose(sqlSession);
 }
result:
user = User{uId='7425dfdc-fd6f-11e9-ae08-d017c2236ed4', uName='珍君', age=12}  主键在插入式就可以查出字符串属性值,因为他是插入方法之前执行的

5. mybatis核心resultMap

resultMap是mapper 中的一个标签,当resultType满足不了结果集映射时候就可以用resultMap

情景:当列名和属性名不一样的时候,

:列名和属性名不一致时的解决方案
1. 在查询语句中给列起别名

注意:当所有列都不匹配时候就会返回null

例如:select a_id aId ,a_name aName from a where a_id=#{aid}

2. sql语句片段

select a_id aId, a_name aName from

引入:

...
3. mybtais开启自动识别映射功能(驼峰命名)
4. resultMap
嵌套结果集

使用连接查询,查询多表之间的信息,通过resultmap分别给属性进行赋值

<resultMap id="map" type="Category">
		//主键用id标签  column 用于指定数据库列名  property:对应实体属性    
     <id column="c_id" property="cId"></id>
 	//主表中有辅表类型的集合用collection propety 集合名字  ofType就是集合泛型
 	//其他列用result 标签column   propety
     <collection property="products" ofType="Product">
         <id column="p_id" property="pId"></id>
     </collection>
</resultMap>
//如果在字表中有主表的引用应该用association标签

5. mybatis核心resultMap多表查询
  1. 表关系分析
    1. 一对一:存在主外键,只不过外键是唯一或者外键直接作为主键
    2. 一对多:存在外间关系,外键没有限制
    3. 多对多:两个表之间没有直接关系,会创建一个中间表,中间表存在两个外键,分别关联两个表的主键。
  2. 数据库实体类设计:

面向对象思想射界实体类;子表中的主表信息应该是一个实体

例如:

(字表)

Product

​ pId;

​ pName;

​ cId;

​ category;

主表:

category;

​ cId;

​ cName;

List list;

主表里面含有子表的集合泛型

设计总结:

子表方:子表方存在主表的外键,外键就是关联主表方的一条记录的对象

所以我们设计字表对应的实体的时候,建议把外键列设计成主表的对象的引用,这样更容易的能获取到主表的数据

主表方:主表方没有直接关联子表但是可以通过主表的id去子表查询很多关联的字表信息

主表和子表也间接的产生了关联。如果有需求,主表中可以显示字表中的信息,就可以放子表的集合

嵌套结果集

就是利用连接查询,将结果一次性的全部查询出来,在resultmap中利用collection\association标签给属性赋值的过程

嵌套结果集的缺点

有时候在多表查询时,我们可能只需要查询一个表中的数据,但是查询除了所有表的信息

这样会降低查询效率。

嵌套查询(分步查询)
向下查询
 @Test
    public  void test8(){
        SqlSession sqlSession = MybatisUtils.openSqlSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectProductByPidQian(1);
        System.out.println("product = " + product);

        System.out.println("product.getCategory() = " + product.getCategory());
        System.out.println("product.getInfo = " + product.getCategory().getInfo());

        MybatisUtils.commitAndClose(sqlSession);
    }
    
    
    
    
    
    //在查询product时候触发category的查询
    <!--嵌套查询-->
    <resultMap id="qiantaoproduct" type="Product">
        <id column="p_id" property="pId"></id>
        <!--向下查询时候需要手动result-->
        <result column="c_id" property="cId"></result>
        <!--触发一个子查询,给category赋值,column根据哪一列作为参数传入到子查询中-->
        <association property="category" javaType="Category" column="c_id"
        select="com.it.mapper.CategoryMapper.selectCategoryByCid">

        </association>
    </resultMap>
    <select id="selectProductByPidQian" resultMap="qiantaoproduct">
        select * from product where p_id=#{pid}
    </select>
    
    <resultMap id="ct" type="Category">
        <id column="c_id" property="cId"></id>
        <!--向下查询时候result不可以省略-->
        <result column="i_id" property="iId"></result>
        <!--并引入info的查询-->
        <association property="info" column="i_id" javaType="Info"
                     select="com.it.mapper.InfoMapper.selectInfoByIid">

        </association>
    </resultMap>
   <select id="selectCategoryByCid" resultMap="ct">
       select * from category where c_id=#{cid}
   </select>
    注意!!!!
    在触发category的查询时候用了column 属性,用于给category的查询传参
   并用select属性传入category查询方法的命名空间和方法名
   
   
   并且再在category里面触发info的查询
   
向上查询:
 @Test
    public  void test10(){
        SqlSession sqlSession = MybatisUtils.openSqlSession();
        InfoMapper mapper = sqlSession.getMapper(InfoMapper.class);
        Info info = mapper.selectInfoAndCategoryAndProduct(1);
        System.out.println("----------------");
        System.out.println("info = " + info);
        List<Category> categories = info.getCategories();
        for (Category category : categories) {
            System.out.println("###############");
            System.out.println(category);
        }

        MybatisUtils.commitAndClose(sqlSession);
    }
    
    <resultMap id="iAndCAndPro" type="Info">
        <id column="i_id" property="iId"></id>
        <!--触发category的查询-->
        <collection property="categories" ofType="Category" column="i_id" select="com.it.mapper.CategoryMapper.selectCategoryAndProductByCid">
            <id column="c_id" property="cId"></id>
        </collection>
    </resultMap>
    <select id="selectInfoAndCategoryAndProduct" resultMap="iAndCAndPro">
        select * from info where i_id=#{iid}
    </select>
    
    
    <!--向上查询-->
    <resultMap id="cAndPro" type="Category">
        <id column="c_id" property="cId"></id>
        <!--出发product的查询-->
        <collection property="products" ofType="Product" column="c_id" select="com.it.mapper.ProductMapper.selectProductByPid">

        </collection>
    </resultMap>

    <select id="selectCategoryAndProductByCid" resultMap="cAndPro">
        select * from category where c_id=#{cid}
    </select>
    
    
    
    result:
    ----------------
    info = Info{iId=1, iInfo='零食好吃可不要贪杯哦', aId=1}
###############
Category{cId=1, cName='零食', iId=1}

6. 动态sql

mybatis提供了一系列的标签,控制sql语句的结构,

<!--动态sql语句
        根据传入的不同的参数二位执行不同的sql语句
    -->
    <select id="selectBlogs" resultType="Blog">
if标签!!!!!!!!!!!
1:需要在where后面添加永远成立条件
2:当只有永远成立条件成立时会查出所有的记录
3:当多个条件成立时会拼接多个条件
        <!--select * from blog where 1=1
        <if test="id != 0">
            and id=#{id}
        </if>
        <if test="title != null">
            and title=#{title}
        </if>
        <if test="content !=null">
            and content=#{content}
        </if>-->
where标签!!!!!!!!
1:标签里面的条件都不满足时候会查询所有信息:
2:会自动添加在表明后添加 where  
3:当第一个条件满足时会自动忽略条件里面的and

        <!--select * from blog
        <where>
            <if test="id != 0">
                and id=#{id}
            </if>
            <if test="title != null">
                and title=#{title}
            </if>
            <if test="content !=null">
                and content=#{content}
            </if>
        </where>-->
        select * from blog where
choose标签 !!!!!!!!
1:当所有的都不符合条件时会走othorwise,会查出所有
2:当有多个条件满足时会默认走最后一个判断,他不会对sql语句进行拼接
        <choose>
            <when test="id !=0">
              id=#{id}
            </when>
            <when test="content !=null">
               content =#{content}
            </when>
            <when test="title !=null">
               title = #{title}
            </when>
            <otherwise>
                1=1
            </otherwise>
        </choose>
    </select>
   <foreach>遍历in
   1:它可以遍历集合
   2:可以遍历数组
   集合:
   </select>
    <select id="selectBlogInids" resultType="Blog">
        select * from blog where id in
        <foreach collection="list" separator="," open="(" close=")" index="it" item="r">
            #{r}
        </foreach>
    </select>
    
    数组
    <select id="selectBlogInids" resultType="Blog">
        select * from blog where id in
        <foreach collection="array" separator="," open="(" close=")" index="it" item="r">
            #{r}
        </foreach>
    </select>
参数说明:
collection:是遍历的数据类型      list|array
separator是分隔符  括号里面的,
open:就是sql语句中的  in ()
close:结束括号
index:下标
item:就是每次便利的一条记录

7. mybatis注解形式进型sql语句编写

注解形式查询适合单表查询,虽然注解查询很简单,但是不建议注解形式查询,因为在xml形式的查询中有

注解形式的查询,不利于系统维护,

注解形式只要在方法上添加注解

@Select(" select * from product where p_id=#{pid}")

Product selectProductById(int pid)

@Delete(“delete from product where p_id=${pid}”)

int deleteProduct(int pId);

8.延迟加载

不在初始化的时候加载,需要等到对象的是属性、方法被调时候,才会被加载

只有嵌套查询时候才会有延迟加载(lazyLoadingEnabled),嵌套结果集没有延迟加载,因为嵌套结果集试一次查询,

触发条件:

有嵌套查询,嵌套查询中的column是传下去的查询条件,为子查询的主键id

查询结果被用时候才会触发被嵌套的查询,没有用时不会查询

lazyLoadingEnabled与aggressiveLazyLoading

aggressiveLazyLoading是按需求加载 积极加载

调用子属性,而且只调用子属性时才能实现单个查询。

ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectProduct(1);
        System.out.println("product = " + product.getpName());
        MybatisUtils.commitAndClose(sqlSession);

9. 缓存

​ #### 一级缓存

缓存:查询的获得的数据在某些情况下不会触发sql语句直接拿到结果,走缓存

他是默认缓存级别

获取缓存:

  1. 同一个sqlsession/
  2. 可以是同个session 但是不同的mapper
  3. 查询的id相同
  4. 两次查询之间不能有dml操作
Detail detail = mapper.selectDetailById(1);
        System.out.println("detail = " + detail);
        System.out.println("___________________");
        
        Detail detail1 = mapper.selectDetailById(1);

        System.out.println("detail1 = " + detail1);

        MybatisUtils.commitAndClose(sqlSession);
result:
==>  Preparing: select * from detail where d_id=? 
==> Parameters: 1(Integer)
<==    Columns: d_id, d_info
<==        Row: 1, 好商品,格力造
<==      Total: 1
detail = Detail{dId=0, dInfo='null'}
___________________
detail1 = Detail{dId=0, dInfo='null'}

        可看出默认走的缓存:
        
    不同mapper也是走缓存
        
    不同sqlsessionFactory 不会走缓存
        
 
DetailMapper mapper = sqlSession.getMapper(DetailMapper.class);
        Detail detail = mapper.selectDetailById(1);
        System.out.println("detail = " + detail);
        System.out.println("___________dml操作________");

        detail.setdId(435);
        detail.setdInfo("bfdkjlbk");
        mapper.insertInto(detail);
        DetailMapper mapper1 = sqlSession.getMapper(DetailMapper.class);
        Detail detail1 = mapper1.selectDetailById(1);
        System.out.println("detail1 = " + detail1);
        
        
result:
==>  Preparing: select * from detail where d_id=? 
==> Parameters: 1(Integer)
<==    Columns: d_id, d_info
<==        Row: 1, 好商品,格力造
<==      Total: 1
detail = Detail{dId=0, dInfo='null'}
___________dml操作________
==>  Preparing: insert into detail(d_id,d_info) values(?,?); 
==> Parameters: 435(Integer), bfdkjlbk(String)
<==    Updates: 1
==>  Preparing: select * from detail where d_id=? 
==> Parameters: 1(Integer)
<==    Columns: d_id, d_info
<==        Row: 1, 好商品,格力造
<==      Total: 1
detail1 = Detail{dId=0, dInfo='null'}

证明中间有mdl 操作不会走缓存,要经过sql 语句

二级缓存

默认二级缓存是关闭的

获取缓存:

  1. 同一个sqlsessionFactory

  2. 默认情况下二级缓存是关闭的,因为参与的用户很多,可能出现很多数据安全问题

  3. 只要两次查询时间没有dml操作清空缓存

  4. 不同的sqlsession和mapper都可以有缓存

学习点:
  1. 如何开启二级缓存

    默认是开起的但是每个mapper文件中又关闭着二级缓存。因此在mapper配置文件中写

  2. 如何这只特定的sql情况

    ​ 开启缓存最大的隐患就是并发情况下获取到了脏数据

    ​ 情景:后台更新频繁的数据,不建议开启二级缓存

    ​ 数据更新不是很频繁时候建议开启二级缓存,例如首页的轮播图

    ​ 或者类别,菜单等

    ​ mapper开启缓存,但是内部特定方法关闭二级缓存

  3. 面试问题:mybatis缓存有什么优势

缓存颗粒度更细:

​ 能控制单个查询方法:usecache:true:开启直接获取缓存不取再查询

false:关闭,直接去查询,不去走缓存,也不会存入缓存

flushcache 刷新缓存,true 先查询新的数据,存入缓存,在缓存中获取数据

false:不刷新。

  1. 总结:二级缓存总开关,每个mapper文件的缓存开关,具体的方法的缓存开关,因此颗粒度小,这是他的一个优点。但是到缓存满了后他会删除缓存,而且用的算法是先进先出类型的,不管活跃度,直接删除,这就是我们为设么一般用第三方缓存的原因

  2. 一般情况下我们会用第三方缓存
    1. 导入依赖:

      net.sf.ehcache ehcache-core 2.6.5 org.mybatis mybatis-ehcache 1.0.0
    2. 开启缓存开关

      1.核心配置文件

      2.mapper写cache标签

    3. 在classpath路径下!写一个cache.xml的缓存配置文件

      LRU:算法! 最近 最少 使用

      LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法

      maxElementsInMemory 超过内存缓存存储数量以后!注意不会再缓存!而不是清空!lru

      lur:当扫描时间到的时候!会统一 算。

      <ehcache >
      				    <!-- 缓存数据要存放的磁盘地址 -->
      				    <diskStore path="D:\develop\ehcache" />
      				    <!-- diskStore:指定数据在磁盘中的存储位置。
      				     defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
      				       以下属性是必须的:  maxElementsInMemory - 在内存中缓存的element的最大数目  maxElementsOnDisk
      				       - 在磁盘上缓存的element的最大数目,若是0表示无穷大  eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
      				        overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 以下属性是可选的:  timeToIdleSeconds
      				       - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
      				        timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 diskSpoolBufferSizeMB
      				       这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.  diskPersistent
      				       - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。  diskExpiryThreadIntervalSeconds
      				       - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作  memoryStoreEvictionPolicy
      				       - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) -->
      
      				    <defaultCache maxElementsInMemory="1000"
      				                  maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false"
      				                  timeToIdleSeconds="120" timeToLiveSeconds="120"
      				                  diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU">
      				    </defaultCache>
      				</ehcache>
              
      

      在缓存满了后会写文件到本地磁盘里面,因此用到了序列化的问题,因此实体类需要实现序列化接口

10.

mybatis分页插件!只需要你正常查询全部sql语句!设置当前页数和页容量!
即可获取所有分页先关的数据!例如:当前页的数据集合!第几页!页容量!中页数!上一页

下一页!等等!

使用分页插件
  1. 写分页插件的依赖

    com.github.pagehelper pagehelper 4.1.6
  2. 核心配置文件中添加插件

  1. 直接食用分页插件就行

    1.设置分页信息(第几页,页容量)

    		       2.查询所有的信息(不用分页查询 limit)
    
    		       3.创建PageInfo
    
    		       4.获取分页信息
    
    		        //分页查询了
    	            //1.设置分页信息
    	            PageHelper.startPage(index, size);
    
    	            SqlSession sqlSession = MybatisUtils.openSqlsession();
    
    	            ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
    
    	            List<Product> products = mapper.selectProductAll();
    
    	            PageInfo<Product> pageInfo = new PageInfo<>(products);
    
    	            MybatisUtils.commitAndClose(sqlSession);
    
    	            //获取所有信息
    
    	            List<Product> list = pageInfo.getList();
    	            System.out.println("当前页的数据" );
    
    	            for (Product product : list) {
    	                System.out.println("product = " + product);
    	            }
    
    	            int pageNum = pageInfo.getPageNum();
    
    	            System.out.println("获取当前页 = " + pageNum);
    
    	            boolean hasNextPage = pageInfo.isHasNextPage();
    
    	            System.out.println("是否有下一页 = " + hasNextPage);
    
    	            if (hasNextPage) {
    	                int nextPage = pageInfo.getNextPage();
    	                System.out.println("下一页 = " + nextPage);
    	            }
    
    	            boolean hasPreviousPage = pageInfo.isHasPreviousPage();
    	            System.out.println("是否有上一页 = " + hasPreviousPage);
    
    	            if (hasPreviousPage) {
    	                int prePage = pageInfo.getPrePage();
    	                System.out.println("上一页 = " + prePage);
    	            }
    
    	            long total = pageInfo.getTotal();
    	            System.out.println("总条数 = " + total);
    
    	            int pages = pageInfo.getPages();
    	            System.out.println("总页数 = " + pages);
    
    	            int pageSize = pageInfo.getPageSize();
    	            System.out.println("页容量 = " + pageSize);
    

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值