Mybatis小结

Mybatis

  • 认识mybatis:
    • 官方语言:Mybatis是一款优秀的持久层框架,它支持定制SQL,存储过程,以及高级映射.Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集.Mybatis可以使用简单的XML或注解来配置和映射原生类型,接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
    • 简单来说,Mybatis就是一个操作数据库,用来增删改查的工具.
    • Mybatis是一个半自动的ORM框架 : 什么叫半自动呢,就是可以帮你生成一部分的SQL,主要优点就是支持定制化SQL,这个特性让他能够进行SQL调优
    • 适用场景: 在业务频繁修改的系统,需要进行SQL调优的系统中使用
    • 国内互联网公司用Mybatis的比较多
  • 数据库建表:
    • 既然是需要进行增删改查操作,那么我们先来建表:

      -- 商家表
      create table business(
      business_id int not null auto_increment primary key,
      business_name VARCHAR(255) not null UNIQUE KEY,
      business_password VARCHAR(255) not null
      );
      -- 商品表 
      create table produce(
      produce_id int not null auto_increment primary key,
      produce_name VARCHAR(255) not null,
      produce_price DOUBLE not null,
      produce_number int not null
      );
      -- 新增测试数据
      insert into business VALUES(default,"li","wohenshuai");
      insert into business VALUES(default,"superli","wohenqiang");
      
  • 新建实体类:
    /**
     * 商家类,字段最好与数据库向对应,否则需要自己转.
     * 驼峰命名可以配置mybatis代转
     */
    @Data
    public class Business {
        private int businessId;
        private String bussinessName;
        private String bussinessPassword;
    }
    
    /**
     * 商品类
     */
    @Data
    public class Produce {
        private int produceId;
        private String produceName;
        private String producePrice;
        private String produceNumber;
    }
    
  • 使用JDBC查询:
public class BusinessDaoImp {
  
      public Business findBusinessByBusinessId(int businessId) throws ClassNotFoundException, SQLException {
  
  //        注册驱动
          Class.forName("com.mysql.jdbc.Driver");
  //        获取连接
          Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/liwithmybatis","root","123456");
  //        编写sql
          String sql="select * from business where business_id=?";
  //        获取预编译对象
          PreparedStatement pr = connection.prepareStatement(sql);
  //        填充数据
          pr.setInt(1,businessId);
  //        执行查询操作,获得结果集
          ResultSet resultSet = pr.executeQuery();
          Business business = new Business();
          if (resultSet.next()){
              int id = resultSet.getInt("business_id");
              String name = resultSet.getString("business_name");
              String psw = resultSet.getString("business_password");
              business.setBusinessId(id);
              business.setBussinessName(name);
              business.setBussinessPassword(psw);
          }
          return business;
      }
  }
  • 使用mybatis查询
    • 首先当然是加依赖啦,建一个Maven项目,不熟悉Maven的朋友请去看我前面的博客记录.在pom.xml添加数据库相关依赖和Mybatis的依赖:

      <!--    mysql依赖-->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
          </dependency>
      
          <!--mybatis依赖-->
          <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
          </dependency>
      
    • 配置:Mybatis的主配置:在resources文件夹下面新建一个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>
      <!--    Mybatis的setting配置,这些去官网上面找能找到,有中文版-->
          <settings>
      <!--        是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。-->
              <setting name="mapUnderscoreToCamelCase" value="true"/>
      <!--        打印运行时的日志-->
              <setting name="logImpl" value="STDOUT_LOGGING"/>
          </settings>
        
      <!--    配置类型别名,可以通过别名的方式来减少mapper.xml中的paramerType和resuletType的复杂度-->
          <typeAliases>
              <typeAlias alias="business" type="com.li.mybatis.entity.Business"/>
              <typeAlias alias="produce" type="com.li.mybatis.entity.Produce"/>
      <!--    也可以直接配置包名,这里的别名就是entity包下的类名小写-->
      <!--        <package name="com.li.mybatis.entity"/>-->
          </typeAliases>
      
      <!--    配置JDBC连接数据库-->
          <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/liwithmybatis"/>
                      <property name="username" value="root"/>
                      <property name="password" value="123456"/>
                  </dataSource>
              </environment>
          </environments>
      
      <!--    Mybatis的单表配置,与要查询的表相关联-->
          <mappers>
              <mapper resource="mappers/business-mapper.xml"/>
          </mappers>
          
      </configuration>
      
    • 单表配置:要查询哪张表就配哪张表,一般在resources文件夹下再建一个mappers文件夹用来保存单表的配置:

      <?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可以随便写-->
      <mapper namespace="li">
      
      <!--    字段转换,将实体类的属性与数据库的字段相匹配-->
      <!--    增加-->
          <insert id="insert">
              insert into business values(default,#{businessName},#{businessPassword})
          </insert>
      
      <!--    删除-->
          <delete id="del">
              delete from business where business_id=#{businessId}
          </delete>
      
      <!--    修改-->
          <update id="update">
              update business set business_name=#{businessName} where business_id=#{businessId}
          </update>
      
      <!--    查询-->
          <select id="select" resultType="business">
              select * from business where business_id=#{businessId}
          </select>
      </mapper>
      
    • 测试类:增删改都需要提交(commit)才会生效

      public class App 
      {
          public static void main( String[] args ) throws IOException {
      //        启动mybatis框架
      
      //        读取配置文件,这里注意Resources的包被导错了,是Apache的包
              InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-conf.xml");
      o
      //        构建SQLSessionFactory
              SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
      //        创建SqlSession
              SqlSession sqlSession = factory.openSession();
      //        开始执行方法,注意要提交,不然没有效果,方法的参数("namespace.id",mapper中sql的参数),传实体类注意sql的参数要与实体类的属性相对应
      //        Business business = new Business();
      //        business.setBussinessName("毛毛虫");
      //        business.setBussinessPassword("aichicao");
      //        sqlSession.insert("li.insert",business);
      //        sqlSession.commit();
      
      //        删除
      //        sqlSession.delete("li.del",4);
      //        sqlSession.commit();
      
      //        修改
      //        Business business = new Business();
      //        business.setBusinessId(1);
      //        business.setBusinessName("吴彦祖");
      //        sqlSession.update("li.update",business);
      //        sqlSession.commit();
      
      //        查询
              Business business = sqlSession.selectOne("li.select", 1);
              System.out.println(business);
          }
      }
      
  • Mybatis的Mapper接口方式进行查询
    • dao层的mapper接口:

      public interface ProduceMapper {
      
          List<Produce> findProduce();
      }
      
    • 子表配置:

      <?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">
      <!--注意,这里的namespace要写接口路径-->
      <mapper namespace="com.li.mybatis.dao.ProduceMapper">
      
          <select id="findProduce" resultType="produce">
              select * from produce
          </select>
      
      </mapper>
      
    • 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>
      <!--    Mybatis的setting配置,这些去官网上面找能找到,有中文版-->
          <settings>
      <!--        是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。-->
              <setting name="mapUnderscoreToCamelCase" value="true"/>
      <!--        打印运行时的日志-->
              <setting name="logImpl" value="STDOUT_LOGGING"/>
          </settings>
          
      <!--    配置类型别名,可以通过别名的方式来减少mapper.xml中的paramerType和resuletType的复杂度-->
          <typeAliases>
              <typeAlias alias="business" type="com.li.mybatis.entity.Business"/>
              <typeAlias alias="produce" type="com.li.mybatis.entity.Produce"/>
      <!--    也可以直接配置包名,这里的别名就是entity包下的类名小写-->
      <!--        <package name="com.li.mybatis.entity"/>-->
          </typeAliases>
      
      <!--    配置JDBC连接数据库-->
          <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/liwithmybatis"/>
                      <property name="username" value="root"/>
                      <property name="password" value="123456"/>
                  </dataSource>
              </environment>
          </environments>
      
      <!--    Mybatis的单表配置,与要查询的表相关联-->
          <mappers>
              <mapper resource="mappers/business-mapper.xml"/>
              <mapper resource="mappers/produce-mapper.xml"/>
          </mappers>
      </configuration>
      
    • 测试类:

      public class MapperApp {
          public static void main(String[] args) throws IOException {
              InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-conf.xml");
              SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
              SqlSession sqlSession = factory.openSession();
      
      //        生成一个实现类,实现类通过SQLSession访问xml中特定的语句(全类名.方法)
      //        全类名 <=> namespace
      //        方法名 <=> sql的id
      //        这里produceMapper就是Mybatis根据传入的接口生成一个实现类(代理)
              ProduceMapper produceMapper = sqlSession.getMapper(ProduceMapper.class);
              List<Produce> produces = produceMapper.findProduce();
              System.out.println(produces);
          }
      }
      
  • Mybatis的多表查询:
    • 在实际的应用中,肯定多表连接查询的场景要比单表连接查询多得多,下面,就来展示多表查询

    • mapper接口:

      public interface ProduceMapper {
      
          List<Produce> findProduce();
          
       //    这里使用@Param(参数名)注解与mapper.xml中的#{参数名},参数名要对应,结果用map来接收
          List<Map<String,Object>> finProduceAndByBusiness(@Param("businessId") Integer businessId, @Param("produceId")Integer produceId);
      }
      
    • 子表.xml:

      <!--注意,这里的namespace要写接口路径-->
      <mapper namespace="com.li.mybatis.dao.ProduceMapper">
      
          <select id="findProduce" resultType="produce">
              select * from produce
          </select>
      
          
          <select id="finProduceAndByBusiness" resultType="map">
              select b.business_name,p.produce_name from business b,produce p where b.business_id=#{businessId} and p.produce_id=#{produceId}
          </select>
      
      </mapper>
      
    • 直接写结果吧,测试代码就跟上面的一样了,注意,这里打印出来的map中key是数据库的字段

      控制台会打印出:
      [{business_name=吴彦祖, produce_name=百事可乐}]
      
    • 也可以使用另外的方式,就是重新来一个实体类,这个实体类有所有要连接的表的字段

  • Mybatis的动态SQL
    • mybati的一大重要特征就是生成动态sql,什么是动态sql呢,举个例子:有一个user表,里面有user_id,user_name,user_password,当我们需要对其中的一条数据进行修改的时候,可能会出现修改这条信息的一个字段,也可能是多个字段,那么如果没有动态sql,我们将需要写多条sql来完成不一样的修改,有了动态sql我们就只需要写一条就可以了

    • user类:

      @Data
      public class User {
          private int userId;
          private String userName;
          private String userPassWord;
      }
      
    • Mapper接口:

      public interface UserMapper {
      
          User userQuery(User user);
      }
      
    • 子表.xml:

      <?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.li.mybatis.dao.UserMapper">
      
          <!--    查询-->
          <select id="userQuery" resultType="user">
              select * from user
              <where>
                  <if test="userId!=null">
                      and user_id=#{userId}
                  </if>
                  <if test="userName!=null">
                      and user_name=#{userName}
                  </if>
              </where>
          </select>
      
      </mapper>
      
    • 测试类:

      public class MapperApp {
          public static void main(String[] args) throws IOException {
              InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-conf.xml");
              SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
              SqlSession sqlSession = factory.openSession();
              UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
              //这里只传入了userId
              User user = new User();
              user.setUserId(1);
              User user1 = userMapper.userQuery(user);
              System.out.println(user);
          }
      }
      
    • 这里我们直接看一下生成的sql

      select * from user WHERE user_id=? 
      
    • 将userName也传入后生成的sql

      select * from user WHERE user_id=? and user_name=? 
      
    • 在更新的时候也一样,将where换成set就ok

      <update id="upd" parameterType="user">
              update user
              <set>
                  <if test="userName!=null">
                      ,user_name=#{userName}
                  </if>
                  <if test="userPassword!=null">
                      ,user_password=#{userPassword}
                  </if>
              </set>
              where user_id=#{userId}
          </update>
      
    • choose, when, otherwise ,这里的相当于if , else if, else这种关系

       <select id="cwoFind" parameterType="pro" resultType="pro">
              select * from produce
              <where>
                  <choose>
                      <when test="pId!=0">
                          and p_id=#{pId}
                      </when>
                      <when test="pName!=null">
                          and p_name=#{pName}
                      </when>
                      <otherwise>
                          p_number=111
                      </otherwise>
                  </choose>
              </where>
          </select>
      
    • foreach,当我们需要对一个集合进行遍历,也就是需要使用in(参数1,参数2…)的时候

      <select id="forFind" parameterType="list" resultType="map">
              select * from produce where p_id in
              <foreach collection="list" open="(" close=")" separator="," item="n">
                  #{n}
              </foreach>
          </select>
      这里的几个参数的意思:
      	collection 被迭代的列表
          open  迭代之前加入
          close 迭代之后加入
          separator 迭代时的分隔符
          item  迭代的变量名
      
    • foreach测试类代码:

      //        foreach的测试
              List<Integer> list=new ArrayList<>();
              list.add(1);
              list.add(2);
              list.add(3);
              list.add(4);
              list.add(5);
              List<Produce> produces = userDao.forFind(list);
              System.out.println(produces);
      
    • 生成的sql:

      select * from produce where p_id in ( ? , ? , ? , ? , ? ) 
      
    • trim,trim可以理解为等同于where

      <select id="userQuery" resultType="user">
              select * from user
              <trim prefix="where" prefixOverrides="and" >
                  <if test="userId!=null">
                      and user_id=#{userId}
                  </if>
                  <if test="userName!=null">
                      and user_name=#{userName}
                  </if>
              </trim>
          </select>
      prefix  trim标签内sql语句加前缀
      suffix  。。。。。。。。加后缀
      prefixOverrides 。。。去除多余的前缀
      suffixOverrides 。。。。去除多余的后缀
      
  • Mybatis的缓存:
    • 一级缓存:
      • mybatis的一级缓存指的是Session缓存,一级缓存的作用域默认是一个SqlSession.mybatis默认开启的也是一级缓存.
      • 也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并将数据写入到缓存中,第二次以后执行相同的sql时就是直接去缓存中取.
      • 一级缓存,事务提交后缓存会清空
      • 配置,在setting里面:\<setting name="localCacheScope" value="{SESSION | STATEMENT}"/>
      • 注意:当Mybatis整合Spring后,直接通过Spring注入Mapper的形式,如果不是在同一个事务中,每个Mapper的每次查询操作都对应一个全新的SqlSession实例,这个时候就不会有一级缓存的命中,但是在同一个事务中时共用的是同一个SqlSession。
        如有需要可以启用二级缓存。
    • 我们执行如下测试代码:

      public class App 
      {
          public static void main( String[] args ) throws IOException {
      //        读取配置文件
              InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-conf.xml");
      
      //        构建SQLSessionFactory
              SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
      //        创建SqlSession
              SqlSession sqlSession = factory.openSession();
      //        查询
              Business business = sqlSession.selectOne("li.select", 1);
      //        sqlSession.commit();
              Business business1 = sqlSession.selectOne("li.select", 1);
              System.out.println(business);
              System.out.println(business1);
      
          }
      }
      
    • 看一下控制台打印的日志:这里就没有再另外生成一个sql再去进行数据库查询了

      ==>  Preparing: select * from business where business_id=? 
      ==> Parameters: 1(Integer)
      <==    Columns: business_id, business_name, business_password
      <==        Row: 1, 吴彦祖, wohenshuai
      <==      Total: 1
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      
    • 当我们将SQLSession提交(commit),再来看一下控制台:这里就又产生了一个sql说明进行了一次数据库查询,说明缓存被清空了

      ==>  Preparing: select * from business where business_id=? 
      ==> Parameters: 1(Integer)
      <==    Columns: business_id, business_name, business_password
      <==        Row: 1, 吴彦祖, wohenshuai
      <==      Total: 1
      ==>  Preparing: select * from business where business_id=? 
      ==> Parameters: 1(Integer)
      <==    Columns: business_id, business_name, business_password
      <==        Row: 1, 吴彦祖, wohenshuai
      <==      Total: 1
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      
    • 二级缓存:
      • mybatis的二级缓存是指mapper映射文件.二级缓存的作用域是同一个namespace的mapper映射文件内容,多个SqlSession共享.Mybatis需要手动设置启动二级缓存.

      • 二级缓存是默认启用的(要生效需要对每个Mapper进行配置),如果想取消,则可以通过Mybatis配置文件中的元素下的子元素来指定cacheEnabled为false.

      • 二级缓存在事务提交之后才可以共享,跨SQLSession

      • 配置1:true为开启,默认为开启状态:<setting name="cacheEnabled" value="true"/>

      • 配置2:在需要开启二级缓存的子mapper中添加:

        <!--    开启二级缓存-->
            <cache
                    eviction="LRU"
                    flushInterval="60000"
                    size="512"
                    readOnly="true"/>
        eviction:清除策略,LRU – 最近最少使用:移除最长时间不被使用的对象。
        				FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
        				SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
        				WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
        flushInterval:(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
        size:(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
        readOnly:(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
        
    • 测试代码:

      public class App 
      {
          public static void main( String[] args ) throws IOException {
      //        读取配置文件
              InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-conf.xml");
      
      //        构建SQLSessionFactory
              SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
      //        创建SqlSession
              SqlSession sqlSession = factory.openSession();
      //        查询
              Business business = sqlSession.selectOne("li.select", 1);
              SqlSession sqlSession1 = factory.openSession();
              Business business1 = sqlSession1.selectOne("li.select", 1);
              System.out.println(business);
              System.out.println(business1);
      
          }
      }
      
    • 这时候因为没有提交,所以二级缓存并没有生效,控制台会打印出:就有2遍sql

      ==>  Preparing: select * from business where business_id=? 
      ==> Parameters: 1(Integer)
      <==    Columns: business_id, business_name, business_password
      <==        Row: 1, 吴彦祖, wohenshuai
      <==      Total: 1
      Cache Hit Ratio [li]: 0.0
      Opening JDBC Connection
      Created connection 2009221452.
      Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@77c2494c]
      ==>  Preparing: select * from business where business_id=? 
      ==> Parameters: 1(Integer)
      <==    Columns: business_id, business_name, business_password
      <==        Row: 1, 吴彦祖, wohenshuai
      <==      Total: 1
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      
    • 在执行完第一个sqlsession之后,我们将其提交:

      //        创建SqlSession
              SqlSession sqlSession = factory.openSession();
      //        查询
              Business business = sqlSession.selectOne("li.select", 1);
      		
              SqlSession sqlSession1 = factory.openSession();
              Business business1 = sqlSession1.selectOne("li.select", 1);
              System.out.println(business);
              System.out.println(business1);
      
    • 控制台会打印出:可以这里只出现了一次sql,另一次是从cache里面查询的

      ==>  Preparing: select * from business where business_id=? 
      ==> Parameters: 1(Integer)
      <==    Columns: business_id, business_name, business_password
      <==        Row: 1, 吴彦祖, wohenshuai
      <==      Total: 1
      Cache Hit Ratio [li]: 0.5
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      Business(businessId=1, businessName=吴彦祖, businessPassword=wohenshuai)
      
    • 还可以在一个mapper中引用另一个mapper的缓存配置:

      <!--引用另一个namespace的缓存配置-->
          <cache-ref namespace="com.woniuxy.mybatis.UserDAO"/>
      
  • 二级缓存的使用原则
    • 只能在一个命名空间下使用二级缓存
      由于二级缓存中的数据是基于namespace的,即不同namespace中的数据互不干扰。在多个namespace中若均存在对同一个表的操作,那么这多个namespace中的数据可能就会出现不一致现象。
    • 在单表上使用二级缓存
      如果一个表与其它表有关联关系,那么久非常有可能存在多个namespace对同一数据的操作。而不同namespace中的数据互补干扰,所以就有可能出现多个namespace中的数据不一致现象。
    • 查询多于修改时使用二级缓存
      在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓存,对二级缓存的频繁刷新将降低系统性能。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值