mybatis学习笔记看着一篇就够了!

前言

个人学习笔记,适合复习使用。
参考:https://mybatis.org/mybatis-3/zh/

一:入门

1.依赖

<!--mybatis-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>x.x.x</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>x.x.x</version>
</dependency>
<!--log4j-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

2.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核心配置文件-->
<configuration>
  <!--可以配置多个环境 default默认值-->
  <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>
  <!--注册Mapper(所有mapper都要注册)-->
  <mappers>
      <mapper resource="UserMapper"/>
  </mappers>
</configuration>

3.Mybatis工具类

public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        //1.获取sqlSessionFactory对象
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    //可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

    //2.获得 SqlSession 的实例
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
        //自动提交事务
        //return sqlSessionFactory.openSession(true);
    }
}

4.dao层(映射器)

public interface UserMapper{
    List<User> getUserList();
}

5.映射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">
<!--namespace:与dao层自定义接口一一对应-->
<mapper namespace="com.mhw.dao.UserMapper">
    <!--查询语句-->
    <!--id:对应dao层接口内方法名-->
    <!--resultType:返回类型(包+类名)-->
    <select id="getUserList" resultType="com.mhw.pojo.User">
        Select * from t_user
    </select>
</mapper>

6.使用

SqlSession sqlSession = null;
try {
    //方式一:推荐
    //获取sqlSession
    sqlSession = MybatisUtil.getSqlSession();
    //获取mapper
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //执行sql
    List<User> userList = userMapper.getUserList();
    //方式二:不推荐
    //        List<User> userList = sqlSession.selectList("com.mhw.dao.UserMapper.getUserList");
    //增删改需要提交事务
    //sqlSession.commit();
    for (User user : userList) {
        System.out.println(user.toString());
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
    //使用完了一定要关闭
    assert sqlSession != null;
    sqlSession.close();
}

7.使用注解不是用xml配置

public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  //多个参数时(基本类型+String),因按照规范加上@Param注解。
  Blog selectBlog(@Param("id")int id);
}

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

8.核心类

8.1 SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

8.2 SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

8.3 SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。

9.映射器实例

映射器是一些绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。虽然从技术层面上来讲,任何映射器实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是映射器实例的最合适的作用域。 也就是说,映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃。 映射器实例并不需要被显式地关闭。尽管在整个请求作用域保留映射器实例不会有什么问题,但是你很快会发现,在这个作用域上管理太多像 SqlSession 的资源会让你忙不过来。 因此,最好将映射器放在方法作用域内。

二:配置解析

1.properties(属性)

通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

  • 可以为占位符指定一个默认值。例如:
<dataSource type="POOLED">
  <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->
  <property name="username" value="${username:ut_user}"/> 
</dataSource>
  • 这个特性默认是关闭的。要启用这个特性,需要添加一个特定的属性来开启这个特性。例如:
<properties resource="org/mybatis/example/config.properties">
  <!-- 启用默认值特性 -->
  <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> 
</properties>
  • 如果你在属性名中使用了 ":" 字符(如:db:username),或者在 SQL 映射中使用了 OGNL 表达式的三元运算符(如: ${tableName != null ? tableName : 'global_constants'}),就需要设置特定的属性来修改分隔属性名和默认值的字符。例如:
<properties resource="org/mybatis/example/config.properties">
   <!-- 修改默认值的分隔符 -->
  <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/>
</properties>
<!-- 修改分隔符后使用示例 -->
<dataSource type="POOLED">
  <property name="username" value="${db:username?:ut_user}"/>
</dataSource>

2.类型别名

<!--类型别名-->
<typeAliases>
    <!--类-->
    <typeAlias alias="User" type="com.mhw.pojo.User"/>
    <!--包 使用类的时候用小写-->
    <package name="com.mhw.pojo"/>
</typeAliases>
@Alias("author")
public class Author {
    ...
}

3.映射器(mappers)

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
<!--一下需要pom里面注册资源文件-->
<!-- 使用映射器接口实现类的完全限定类名 接口和xml在一个包下且同名-->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 接口和xml在一个包下且同名-->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

三:XML映射

1.resultMap

<!-- 简单地将所有的列映射到 HashMap 的键上 -->
<!-- mybatis-config.xml 中 -->

<!-- 设置别名 -->
<typeAlias type="com.someapp.model.User" alias="User"/>

<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultMap="userResultMap">
  select
    user_id,
    user_name,
    hashed_password
  from some_table
  where id = #{id}
</select>
<!-- resultMap -->
<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>


<!-- MyBatis 会在幕后自动创建一个 ResultMap -->
<select id="selectUsers" resultType="User">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
  from some_table
  where id = #{id}
</select>

五:日志

Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging
<configuration>
  <settings>
     <!-- 可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING -->
    <setting name="logImpl" value="LOG4J"/>
  </settings>
</configuration>
  • STDOUT_LOGGING标准输出
Opening JDBC Connection
Created connection 942518407.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@382db087]
==>  Preparing: select * from t_user
==> Parameters: 
<==    Columns: id, name, pwd
<==        Row: 1, 小明, 123456
<==      Total: 1
User{id=1, name='小明', pwd='123456'}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@382db087]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@382db087]
Returned connection 942518407 to pool.

1.使用Log4j

### 配置文件 最好放在resources下###
### 设置 ###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
//loh4j初始化 配置不生效的时候使用
public class InitLogRecord {
    public static void initLog() {
        FileInputStream fileInputStream = null;
        try {
            Properties properties = new Properties();
            fileInputStream = new FileInputStream("src/main/resources/log4j");
            properties.load(fileInputStream);
            PropertyConfigurator.configure(properties);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
<settings>
    <setting name="logImpl" value="LOG4J"/>
</settings>
static Logger logger = Logger.getLogger(UserMapperTest.class);
//输出不同级别的日志
logger.debug("debug:执行托尔斯泰");
logger.info("info:执行托尔斯泰");
logger.error("error:执行托尔斯泰");
logger.warn("warn:执行托尔斯泰");

六:分页

1.limit

SELECT * FROM t_user LIMIT startIndex,pageSize;

2.RowBounds

//很少使用
RowBounds rowBounds = new RowBounds(startIndex,pageSize);
List<User> userList = sqlSession.selectList("com.mhw.dao.UserMapper.getByRowBounds",null,rowBounds);

3.PageHelper(推荐)

  • 文档:https://pagehelper.github.io/docs/howtouse/

七:Mybatis执行流程

  1. 获取配置文件 Resources.getResourceAsStream(resource);
  2. 实例化SqlSessionFactoryBuilder new SqlSessionFactoryBuilder()
  3. XMLConfigBuilder解析配置文件流 new XMLConfigBuilder(reader, environment, properties);
  4. 配置所有信息 new DefaultSqlSessionFactory(config);
  5. 实例化sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream);
  6. 创建事务管理器transaction
  7. 创建执行器executor
  8. 创建sqlSession
  9. 执行CRUD(与事务管理器相联系,涉及回滚)
  10. 判断执行是否成功,成功则提交事务并关闭sqlSession,失败则回滚。

八:复杂查询

数据库准备:

DROP TABLE
IF EXISTS `teacher`;

CREATE TABLE `teacher` (
	`t_id` INT (10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
	`t_name` VARCHAR (30) DEFAULT NULL
) ENGINE = INNODB DEFAULT CHARSET = utf8 

INSERT INTO teacher (`t_name`) VALUES ('缪老师');

DROP TABLE
IF EXISTS `student`;

CREATE TABLE `student` (
	`s_id` INT (10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
	`s_name` VARCHAR (30) DEFAULT NULL,
	`t_id` INT (10) NOT NULL,
	FOREIGN KEY (`t_id`) REFERENCES `teacher` (`t_id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8 

INSERT INTO student (`s_name`,`t_id`) VALUES ('康康娃1', 1);
INSERT INTO student (`s_name`,`t_id`) VALUES ('康康娃2', 1);
INSERT INTO student (`s_name`,`t_id`) VALUES ('康康娃3', 1);
INSERT INTO student (`s_name`,`t_id`) VALUES ('康康娃4', 1);
INSERT INTO student (`s_name`,`t_id`) VALUES ('康康娃5', 1);
INSERT INTO student (`s_name`,`t_id`) VALUES ('康康娃6', 1);
INSERT INTO student (`s_name`,`t_id`) VALUES ('康康娃7', 1);

1.多对一(关联)

SELECT s.s_id sid,s_name sname,t.t_name tname FROM student s,teacher t WHERE s.t_id=t.t_id
<!-- 方式一:子查询 -->
<mapper namespace="com.mhw.dao.StudentMapper">
    <resultMap id="studentInfo" type="Student">
        <result property="id" column="s_id" />
        <result property="name" column="s_name"/>
        <!-- javaType 返回值类型 -->
        <!-- column 与原始列名相同 -->
        <association property="teacher" column="t_id" javaType="Teacher" select="getTeacherInfoById"/>
    </resultMap>
    <select id="getStudentInfo" resultMap="studentInfo">
        SELECT * FROM student
    </select>
    <select id="getTeacherInfoById" resultType="Teacher">
        <!-- #{}需按规范书写 一般他会自己推断 -->
        SELECT * FROM teacher WHERE t_id = #{id}
    </select>
</mapper>
<!-- 方式二:连表查询 -->
<mapper namespace="com.mhw.dao.StudentMapper">
    <resultMap id="studentInfo" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <!-- javaType 返回值类型 -->
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>
    <select id="getStudentInfo" resultMap="studentInfo">
         SELECT s.s_id sid,s_name sname,t.t_name tname FROM student s,teacher t WHERE s.t_id=t.t_id
    </select>
</mapper>

注意点:property必须与pojo中类属性名一致。

2.一对多(集合)

SELECT s.s_id sid,s.s_name sname,t.t_id tid ,t.t_name tname FROM student s,teacher t WHERE s.t_id = t.t_id ANd t.t_id = #{id}
<!-- 方式一:子查询 -->
<mapper namespace="com.mhw.dao.TeacherMapper">
    <resultMap id="teacherInfo" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="studentList" javaType="ArrayList" ofType="Student" select="getStudentById" column="tid"/>
    </resultMap>
    <!-- ofType 集合的泛型类型 -->
    <select id="getTeacherInfo" resultMap="teacherInfo">
        SELECT t.t_id tid,t.t_name tname FROM teacher t WHERE t.t_id = #{id}
    </select>
    <select id="getStudentById" resultType="Student">
        SELECT * FROM student WHERE t_id = #{tid}
    </select>1
</mapper>
<!-- 方式二:连表查询 -->
<mapper namespace="com.mhw.dao.TeacherMapper">
    <resultMap id="teacherInfo" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!-- ofType 集合的泛型类型 -->
        <collection property="studentList" javaType="ArrayList" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>

    <select id="getTeacherInfo" resultMap="teacherInfo">
        SELECT s.s_id sid,s.s_name sname,t.t_id tid ,t.t_name tname FROM student s,teacher t WHERE s.t_id = t.t_id ANd t.t_id = #{id}
    </select>
</mapper>

九:动态SQL

数据库准备:

DROP TABLE
IF EXISTS `blog`;

CREATE TABLE `blog` (
	`id` INT (10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
	`title` VARCHAR (100) NOT NULL,
	`author` VARCHAR (100) NOT NULL,
	`creat_time` datetime NOT NULL,
	`views` INT (30) NOT NULL
) ENGINE = INNODB DEFAULT CHARSET = utf8 

INSERT INTO `blog` VALUES ('1', '康康娃喜欢吃冰淇淋', '缪老师', '2020-03-02 00:00:00', '301');
INSERT INTO `blog` VALUES ('2', '康康娃喜欢吃冰淇淋1', '缪老师', '2020-03-02 00:00:00', '251');
INSERT INTO `blog` VALUES ('3', '康康娃喜欢吃冰淇淋2', '马老师', '2020-03-02 00:00:00', '500');
INSERT INTO `blog` VALUES ('4', '康康娃喜欢吃冰淇淋3', '缪老师', '2020-03-02 00:00:00', '1000');
INSERT INTO `blog` VALUES ('5', '康康娃喜欢吃冰淇淋4', '马老师', '2020-03-02 00:00:00', '100');
INSERT INTO `blog` VALUES ('6', '康康娃喜欢吃冰淇淋5', '缪老师', '2020-03-02 00:00:00', '255');

1.if、where

根据条件拼接SQL。

<mapper namespace="com.mhw.dao.BlogMapper">
    <!-- parameterType:参数类型 -->
    <select id="getBlogIf" resultType="Blog" parameterType="map">
        select * from blog
        <where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>
</mapper>
SqlSession sqlSession = MybatisUtil.getSqlSession();
BlogMapper blogMapper =  sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("author","马老师");
List<Blog> blogList = blogMapper.getBlogIf(map);

for (Blog blog : blogList) {
    System.out.println(blog.toString());
}
sqlSession.close();

2.choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

<mapper namespace="com.mhw.dao.BlogMapper">
    <select id="getBlogChoose" resultType="Blog" parameterType="map">
        select * from blog where 1=1
        <!-- 对比switch  -->
        <choose>
            <when test="title != null">
                AND title like #{title}
            </when>
            <when test="author != null">
                AND author like #{author}
            </when>
            <otherwise>
                AND views > 500
            </otherwise>
        </choose>
    </select>
</mapper>
SqlSession sqlSession = MybatisUtil.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("author", "%老师%");
List<Blog> blogList = blogMapper.getBlogChoose(map);

for (Blog blog : blogList) {
    System.out.println(blog.toString());
}
sqlSession.close();

3.set

set用于动态包含需要更新的列,忽略其它不更新的列。

<mapper namespace="com.mhw.dao.BlogMapper">
    <update id="updateAuthor" parameterType="map">
        update blog
        <!-- set动态更新数据 除了最后一个外末尾都要加 逗号 -->
        <set>
            <if test="author != null">author=#{author}</if>
        </set>
        where id=#{id}
    </update>
</mapper>
SqlSession sqlSession = MybatisUtil.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("author", "孟老师");
map.put("id", "1");
blogMapper.updateAuthor(map);
//提交事务不要忘记!!
sqlSession.commit();
sqlSession.close();

4.foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

<mapper namespace="com.mhw.dao.BlogMapper">
    <select id="selectAuthorIn" resultType="Blog" parameterType="map">
        select * from blog
        <where>
            <if test="author != null">
                author in
                <!-- open:开始 separator:间隔 close:结尾 -->
                <!-- collection:迭代数据 -->
                <foreach item="item" index="index" collection="list"
                         open="(" separator="," close=")">
                    #{item}
                </foreach>
            </if>
        </where>
    </select>
</mapper>
InitLogRecord.initLog();
SqlSession sqlSession = MybatisUtil.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
List<String> list = new ArrayList<String>();
list.add("马老师");
list.add("康老师");
map.put("author", "马老师");
map.put("list", list);
List<Blog> blogList = blogMapper.selectAuthorIn(map);

for (Blog blog : blogList) {
System.out.println(blog.toString());
}
sqlSession.close();

十:缓存

1.一级缓存

  • 默认开启

  • SqlSession sqlSession = MybatisUtil.getSqlSession();sqlSession.close();之间。

  • 增删改可能会使查缓存失效,所以执行增删改会更新查的缓存。

  • 未关闭前调用mapper同一方法2次,只执行一次sql。

    [DEBUG] 2021-03-02 20:46:33,008 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
    ==>  Preparing: select * from blog where 1=1 AND author like ?
    [DEBUG] 2021-03-02 20:46:33,031 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
    ==> Parameters: %老师%(String)
    [DEBUG] 2021-03-02 20:46:33,045 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
    <==      Total: 1
    Blog(id=1, title=康康娃喜欢吃冰淇淋, author=孟老师, creatTime=Mon Mar 02 00:00:00 CST 2020, views=301)
    ==================================
    Blog(id=1, title=康康娃喜欢吃冰淇淋, author=孟老师, creatTime=Mon Mar 02 00:00:00 CST 2020, views=301)
    

2.二级缓存(全局缓存)

 <!-- 默认是开启的 为了增强代码可读性需显示书写 -->
<setting name="cacheEnabled" value="true"/>

SQL 映射文件里添加:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

eviction(清除策略):

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

lushInterval(刷新间隔):

  • 可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

size(引用数目):

  • 可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。

readOnly(只读):

  • 可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false
SqlSession sqlSession = MybatisUtil.getSqlSession();
SqlSession sqlSession2 = MybatisUtil.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
BlogMapper blogMapper2 = sqlSession2.getMapper(BlogMapper.class);

HashMap map = new HashMap();
map.put("author", "%老师%");

List<Blog> blogList = blogMapper.getBlogChoose(map);
for (Blog blog : blogList) {
    System.out.println(blog.toString());
}
sqlSession.close();

System.out.println("==================================");
List<Blog> blogList2 = blogMapper2.getBlogChoose(map);
for (Blog blog : blogList2) {
    System.out.println(blog.toString());
}
sqlSession2.close();
[DEBUG] 2021-03-02 21:38:39,455 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==>  Preparing: select * from blog where 1=1 AND author like ?
[DEBUG] 2021-03-02 21:38:39,495 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==> Parameters: %老师%(String)
[DEBUG] 2021-03-02 21:38:39,511 method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
<==      Total: 1
Blog(id=6, title=康康娃喜欢吃冰淇淋5, author=缪老师, creatTime=Mon Mar 02 00:00:00 CST 2020, views=255)
==================================
Blog(id=6, title=康康娃喜欢吃冰淇淋5, author=缪老师, creatTime=Mon Mar 02 00:00:00 CST 2020, views=255)

工作机制:

  1. 一个会话(sqlSession)查询一个数据,这个数据就会被放在会话的一级缓存里面。
  2. 会话(sqlSession)关闭了,一级缓存就会被保存在二级缓存。
  3. 新的会话(sqlSession)就可以在二级缓存里面获取需要的信息。
  4. 二级缓存(全局缓存)的存放是以namespace区分的。

3.缓存原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DTfZN28Y-1614694725678)(C:%5CUsers%5C11324%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210302215950744.png)]

  • 首先查找二级缓存
  • 在查找一级缓存
  • 最后再查询数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值