Mybatis:总体的学习笔记

    科技2024-11-06  8

    MyBatis学习

    备注:官方文档

    本篇文章通过:b站的狂神说进行学习

    初识MyBatis

    第一个程序(简单的实现增删改查):

    工程目录

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9urGmvHF-1602072233304)(F:/文档/typora文档/mybatis/img/屏幕截图 2020-09-25 090027.jpg)]

    代码

    配置文件

    <?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> <!-- 默认使用环境--> <environments default="development"> <!-- 定义环境id--> <environment id="development"> <!-- 事务管理器的配置 JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。 MANAGED(了解) – 这个配置几乎没做什么。(过时了没有)--> <transactionManager type="JDBC"/> <!-- 数据源的配置 UNPOOLED(了解)– 这个数据源的实现会每次请求时打开和关闭连接。(没有池的概念) POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间 备注:数据连接池就是用完可以回收 JNDI(了解) – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!--映射器--> <mappers> <mapper resource="com/minjiang/UserMapper.xml"/> </mappers> </configuration>

    接口

    public interface UserMapper { /**查询所有 * * @return */ public List<User> selectAll(); /** * 条件查询 * @param id * @return */ public User selectById(int id); /** * 增加用户 * @param user * @return */ public int addUser(User user); /** * 修改用户 * @param usr * @return */ public int updateUser(User usr); /** * 根据id删除用户 * @param id * @return */ public int deleteUser(int id); } 实体类 public class User { private int id; private String name; private String pwd; public User(){ } public User(int id, String name, String pwd){ this.id = id; this.name = name; this.pwd =pwd; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } } 工具类 /** * 工具类: * 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的 */ public class MybatisUtils { private static String resource = "mybatis-config.xml"; /** * 保证只有一个 */ private static InputStream inputStream; private static SqlSessionFactory sqlSessionFactory; /** * 保证可以直接调用,静态代码块只能用静态类 */ static { try { inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /**SqlSessionFactory,可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法 * * @return */ public static SqlSession getSession(){ SqlSession session = sqlSessionFactory.openSession(); return session; } } 映射文件 <?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.minjiang.mapper.UserMapper"> <select id="selectAll" resultType="com.minjiang.projo.User"> select * from mybatis.user </select> <select id="selectById" resultType="com.minjiang.projo.User" parameterType="com.minjiang.projo.User"> select * from mybatis.user where id = #{id} </select> <insert id="addUser" parameterType="com.minjiang.projo.User"> insert into mybatis.user value (#{id}, #{name}, #{pwd}) </insert> <update id="updateUser" parameterType="com.minjiang.projo.User"> update mybatis.user set name = #{name}, pwd = #{pwd} where id = #{id} </update> <delete id="deleteUser" parameterType="com.minjiang.projo.User"> delete from mybatis.user where id = #{id} </delete> </mapper> 测试文件 public class MyBtaisTest { SqlSession session = MybatisUtils.getSession(); UserMapper mapper = session.getMapper(UserMapper.class); @Test public void selectAllTest(){ // 方法1 // List<User> users = session.selectList("com.minjiang.mapper.UserMapper.selectAll"); //方法2(推荐) List<User> users = mapper.selectAll(); for (User user : users){ System.out.println(user); } session.close(); } @Test public void selectById(){ User user =mapper.selectById(1); System.out.println(user); session.close(); } @Test public void addUser(){ int i = mapper.addUser(new User(5, "小红", "456")); if (i > 0){ System.out.println("添加成功"); } //提交事务 session.commit(); session.close(); } @Test public void updateUser(){ User user = mapper.selectById(3); user.setName("小黑"); int i = mapper.updateUser(user); if (i > 0){ System.out.println("修改成功"); } //提交事务 session.commit(); session.close(); } @Test public void deleteUser(){ int i =mapper.deleteUser(5); if (i > 0){ System.out.println("删除成功"); } //提交事务 session.commit(); session.close(); } }

    注意点:

    ​ 增删改操作都需要提交事务

    mybatis的便利使用(mapper)

    备注:可以给用于参数过多使用,当然一直使用这种方式是极好的

    查询方法

    接口:

    /** * 直接通过键值对的方式(这里的对象名可以随意取) * 参数直接传Map * @param map * @return */ public User selectUserByNP2(Map<String,Object> map);

    映射文件:

    <!-- 传递参数为map--> <select id="selectUserByNP2" resultType="com.minjiang.projo.User" parameterType="map"> select * from user where name = #{username} and pwd = #{password} </select>

    测试文件:

    @Test public void selectUserByNP2(){ //创建一个会话 SqlSession session = MybatisUtils.getSession(); //通过会话创获取一个mapper(映射)对象 UserMapper mapper = session.getMapper(UserMapper.class); Map<String,Object> map = new HashMap<String, Object>(); map.put("username","小白"); map.put("password","456"); //映射文件中中包含着映射出来的方法 User user = mapper.selectUserByNP2(map); System.out.println(user); //提交事务 session.commit(); //关闭事务 session.close(); }

    添加方法

    接口

    /** * 通过键值对进行增加 */ public int addUserByNP2(Map<String,Object> map);

    映射文件

    测试

    @Test public void addUserByNP2(){ //创建一个会话 SqlSession session = MybatisUtils.getSession(); //通过会话创获取一个mapper(映射)对象 UserMapper mapper = session.getMapper(UserMapper.class); Map<String,Object> map = new HashMap<String, Object>(); map.put("id",3); map.put("userName","红蓝CP"); int i = mapper.addUserByNP2(map); if (i > 0){ System.out.println("添加成功"); } //提交事务 session.commit(); //关闭事务 session.close(); } <!-- 传递参数为map--> <insert id="addUserByNP2" parameterType="map"> insert into user(id,name) value (#{id},#{userName}) </insert>

    好处:

    ​ 无需要去改动实体类的东西,提高了效率

    模糊查询

    接口类: /** * 模糊查询 * @param name * @return */ public List<User> selectLike(String name); 映射文件 <select id="selectLike" parameterType="String" resultType="com.minjiang.projo.User"> select * from mybatis.user where name like #{id} </select> 测试类: @Test public void selectLike(){ //创建一个会话 SqlSession session = MybatisUtils.getSession(); //通过会话创获取一个mapper(映射)对象 UserMapper mapper = session.getMapper(UserMapper.class); //映射文件中中包含着映射出来的方法 List<User> users = mapper.selectLike("%白%"); for (User user : users){ System.out.println(user); } //提交事务 session.commit(); //关闭事务 session.close(); }

    配置解析

    配置展示(备注:这也是mybaits的核心配置文件)

    <?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> <!-- 默认使用环境--> <environments default="development"> <!-- 定义环境id--> <environment id="development"> <!-- 事务管理器的配置 JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。 MANAGED(了解) – 这个配置几乎没做什么。(过时了没有)--> <transactionManager type="JDBC"/> <!-- 数据源的配置 UNPOOLED(了解)– 这个数据源的实现会每次请求时打开和关闭连接。(没有池的概念) POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间 备注:数据连接池就是用完可以回收 JNDI(了解) – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!--映射器--> <mappers> <mapper resource="com/minjiang/UserMapper.xml"/> </mappers> </configuration>

    MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

    configuration(配置) properties(属性)settings(设置)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象工厂)plugins(插件)environments(环境配置) environment(环境变量) transactionManager(事务管理器)dataSource(数据源) databaseIdProvider(数据库厂商标识)mappers(映射器)

    重点:注意配置文档的顶层结构顺序,顺序不对会报错

    环境配置

    ​ mybatis可以配置成适应多种环境

    <!-- 默认使用环境--> <environments default="development"> <!-- 定义环境(development)--> <environment id="development"...> </environment> <environment id="test"...> </environment> </environments>

    切换成不同的环境

    <!-- 默认使用环境,可以用于切换,切换成相对应的id就可以了--> <environments default="development">

    属性设置

    另一种配置方式(配置文件的改变==》请根据配置文档的顶层结构顺序配置):

    <properties> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value=" jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8"/> <property name="userName" value="root"/> <property name="password" value="root"/> </properties> <dataSource type="POOLED"> <!-- 可以使用${XXX}进行调用--> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${userName}"/> <property name="password" value="${password}"/> </dataSource>

    备注:详细看官方文档

    简要概括要点:

    事务管理器(transactionManager):JDBC、MANAGED(了解) JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作 MANAGED(了解) – 这个配置几乎没做什么。(过时了没有)

    数据源(dataSource):UNPOOLED(了解)、POOLED(关注点)、JNDI(了解)

    UNPOOLED(了解)– 这个数据源的实现会每次请求时打开和关闭连接。(没有池的概念) POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间 备注:数据连接池就是用完可以回收 JNDI(了解) – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,

    配置设置

    太多了。。。看官方文档吧(条件:只要有遵守文档的顶层结构顺序配置可以了)

    配置文件中的mappers元素

    mappers(映射器):定义SQL语句文件

    映射文件文件的引用方法

    方法1(推荐)

    <!--映射器--> <mappers> <mapper resource="com/minjiang/UserMapper.xml"/> </mappers>

    方法2

    <!--映射器--> <mappers> <!-- <mapper resource="com/minjiang/UserMapper.xml"/>--> <mapper class="com.minjiang.mapper.UserMapper"></mapper> </mappers>

    ​ 注意点:用类去注册

    ​ 映射文件和接口要放在同一目录下,同时文件要相同

    方法3:

    <!--映射器--> <mappers> <!-- <mapper resource="com/minjiang/UserMapper.xml"/>--> <package name="com.minjiang.mapper"/> </mappers>

    ​ 注意点:用类去注册

    ​ 映射文件和接口要放在同一目录下,同时文件要相同

    标注:typeHandlers(类型处理器),objectFactory(对象工厂),plugins(插件)==》推荐(mybatis-Plus)了解即可

    优化代码

    优化1.0

    可以通过引入外部配置简化外部文件

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MudAE6Ka-1602072233306)(img/屏幕截图 2020-09-25 152515.jpg)]

    外部文件:

    driver = com.mysql.jdbc.Driver url = jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8 userName = root password = root

    配置文件的改变(请根据配置文档的顶层结构顺序配置):

    <!--导入文件properties配置文件--> <properties resource="db.properties"></properties> <dataSource type="POOLED"> <!-- 在导入外部文件后,可以使用${XXX}进行调用--> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${userName}"/> <property name="password" value="${password}"/> </dataSource>

    优化2.0(类型别名)

    配置文件的改变(请根据配置文档的顶层结构顺序配置):

    <!-- 类型别名--> <typeAliases> <typeAlias alias="user" type="com.minjiang.projo.User"></typeAlias> </typeAliases>

    映射文件的改变:

    <select id="selectById" resultType="user" parameterType="user"> select * from mybatis.user where id = #{id} </select>

    映射

    结果集映射

    简介:

    强调!!!!resultMap 元素是 MyBatis 中最重要最强大的元素

    1、resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。

    2、ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

    带问题举例(java的实体类属性和数据库的字段不同)

    public class User { private int id; private String name; //passWord和数据库的字段不同 private String passWord; public User() { } public User(int id, String name, String passWord) { this.id = id; this.name = name; this.passWord = passWord; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassWord() { return passWord; } public void setPassWord(String passWord) { this.passWord = passWord; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", passWord='" + passWord + '\'' + '}'; } }

    解决方法

    1、在映射文件中的查询语句添加别名

    <mapper namespace="com.minjiang.mapper.UserMapper"> <select id="selectAll" resultType="user"> select id, name, pwd as passWord from mybatis.user </select> </mapper>

    2、启用结果集映射(推荐)

    <mapper namespace="com.minjiang.mapper.UserMapper"> <resultMap id="UserMap" type="user"> <!-- 设置主键--> <id column="id" property="id"></id> <!-- column是数据库表的列名 , property是对应实体类的属性名 --> <result column="name" property="name"></result> <!-- ===================================================================--> <!-- 熟悉之后,只要添加与数据库不同的部分就可以了(这就是自动手动的混合策略)--> <result column="pwd" property="passWord"></result> </resultMap> <select id="selectAll" resultMap="UserMap"> select * from mybatis.user </select> </mapper>

    自动映射

    在简单的场景下,MyBatis 可以为你自动映射查询结果。

    在 ResultSet 出现的列,如果没有设置手动映射,将被自动映射。

    <resultMap id="map" type="user"></resultMap> <select id="selectById" resultMap="map"> select * from mybatis.user where id=#{id} </select>

    总结

    但如果遇到复杂的场景,你需要构建一个结果映射。混合使用这两种策略

    备注

    无论设置的自动映射等级是哪种,你都可以通过在结果映射上设置 autoMapping 属性来为指定的结果映射设置启用/禁用自动映射(mybatis默认autoMapping 属性为true)。

    <resultMap id="userResultMap" type="User" autoMapping="false"> <result property="password" column="hashed_password"/> </resultMap>

    注释开发

    普及概念(面对接口编程)

    ​ 面对接口编程

    根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好

    Mybatis的注释开发

    备注:maybatis提供的基于注解的的配置java注解的表达力和灵活性十分有限。mybatis映射并不能用注解来构建

    sql 类型主要分成 :

    @select ()@update ()@Insert ()@delete ()

    **注意:**利用注解开发就不需要mapper.xml映射文件了 .


    运用注解的查询例子

    1、添加接口方法

    public interface UserMapper { @Select("select * from user") public List<User> selectAll(); }

    2、修改核心配置文件

    <mappers> <mapper class="com.minjiang.mapper.UserMapper"></mapper> </mappers>

    3、测试文件

    public class TestUserMapper { @Test public void selectAll(){ //获取会话 SqlSession session = MybatisUtils.getSession(); //获取映射文件 UserMapper mapper = session.getMapper(UserMapper.class); //通过映射文件调用方法 List<User> users = mapper.selectAll(); // 遍历得出结果 for(User user : users){ System.out.println(user); } } }

    日志

    作用:测试SQL的时候,有更快的排错效率

    Mybatis 通过使用内置的日志工厂提供日志功能

    SLF4JApache Commons LoggingLog4j 2Log4jJDK logging

    Mybatis会(按上面罗列的顺序)使用第一个查找到的实现。当没有找到这些实现时,将会禁用日志功能。

    标准日志实现

    指定 MyBatis 应该使用哪个日志记录实现。如果此设置不存在,则会自动发现日志记录实现。

    <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>

    测试,可以看到控制台有大量的输出!我们可以通过这些输出来判断程序到底哪里出了Bug

    备注

    value可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING

    mybatis中log4j的实现

    简介:

    Log4j是Apache的一个开源项目通过使用Log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件…我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

    步骤

    1、导入依赖

    <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>

    2、配置文件编写

    #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码 log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/kuang.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG

    3、在Mybatis的核心配置文件中进行设置(注意:)

    <!-- log4j日志输出--> <settings> <setting name="logImpl" value="LOG4J"/> </settings>

    4、测试:

    public class TestUserMapper { //获取当前类的日志 Logger logger = Logger.getLogger(TestUserMapper.class); @Test public void selectAll(){ //可以有选择的输入一些提示信息 logger.info("info:进入selectUser方法"); logger.debug("debug:进入selectUser方法"); logger.error("error: 进入selectUser方法"); } }

    注意点:导包为org.apache.log4j.Logger

    结果:不仅可以在控制台输出,还可以生成一个日志文件【看不到的可以尝试下重新启动软件或是重新生成下目录】

    动态SQL

    推荐官方文档讲的足够清除的了

    重点掌握:if 语句、Where、Set、choose语句、SQL片段

    SQL片段

    有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

    提取SQL片段:

    <sql id="if-title-author"> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </sql>

    引用SQL片段:

    <select id="queryBlogIf" parameterType="map" resultType="blog"> select * from blog <where> <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace --> <include refid="if-title-author"></include> <!-- 在这里还可以引用其他的 sql 片段 --> </where> </select>

    注意:

    ①、最好基于 单表来定义 sql 片段,提高片段的可重用性

    ②、在 sql 片段中不要包括 where

    Mybatis:缓存的使用

    缓存的认知

    缓存定义:存在内存中的临时数据

    缓存的目的:将经常查询的数据放在缓存中,用户不用从磁盘上(关系型数据库数据文件)查询

    缓存的使用数据:经常查询并且不经常改变的数据。

    备注:在mybatis中分为一级缓存和二级缓存

    一级缓存(本地缓存)

    简介

    与数据库同一次会话期间查询到的数据会放在本地缓存中(如果获取相同的数据,直接从缓存中拿,没必须再去查询数据库)(在mybatis中默认开启)

    实体

    public class User { private int id; private String name; private String pwd; public User(){ } public User(int id, String name, String pwd){ this.id = id; this.name = name; this.pwd =pwd; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "com.minjiang.pojo.User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }

    接口

    public interface UserMapper { /** * 条件查询 * @param id * @return */ public User selectById(@Param("id") int id); }

    映射文件

    <?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.minjiang.mapper.UserMapper"> <select id="selectById" parameterType="_int" resultType="user"> select * from mybatis.user where id = #{id} </select> </mapper>

    工具类

    public class MyBatisUtils { private static String resource = "mybatis-config.xml"; private static InputStream inputStream; private static SqlSessionFactory sqlSessionFactory; static { try { inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSession(){ SqlSession session = sqlSessionFactory.openSession(); return session; } }

    测试

    public class CacheTest02 { /** * 开启日志 * */ Logger logger = Logger.getLogger(CacheTest02.class); @Test public void selectById(){ SqlSession session = MyBatisUtils.getSession(); UserMapper mapper = session.getMapper(UserMapper.class); UserMapper mapper1 = session.getMapper(UserMapper.class); User user = mapper.selectById(1); User user1 = mapper1.selectById(1); System.out.println(user); System.out.println(user1); System.out.println(user == user1); //要记住关闭缓存,不然可能会无法使用 session.close(); } }

    结果

    可以通过显示的日志发现查询语句只执行了一次

    备注

    默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)

    为便于以后的维护建议显性表示

    一级缓存失败的四种情况

    1、sqlSession不同(每个sqlSession中的缓存相互独立)

    2、sqlSession相同,你要的查询条件不同(缓存会进行刷新)

    3、sqlSession相同,两次查询之间执行了增删改操作!(缓存会进行刷新)

    4、sqlSession相同,手动清除一级缓存

    清除一级缓存

    SqlSession session = MybatisUtils.getSession(); session.clearCache();

    关闭缓存

    SqlSession session = MybatisUtils.getSession(); session.close();

    二级缓存(全局缓存)

    简介

    基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

    工作机制

    一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;新的会话查询信息,就可以从二级缓存中获取内容;不同的mapper查出的数据会放在自己对应的缓存(map)中;

    备注

    默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件(只作用于一个映射文件)中添加一行:

    <cache/>

    建议同时开启全局缓存 【mybatis-config.xml】(便于维护)

    <setting name="cacheEnabled" value="true"/>

    配置二级缓存

    1、开启全局缓存 【mybatis-config.xml】(官方文档规定)

    <setting name="cacheEnabled" value="true"/>

    2、在映射文件中配置(只作用于一个映射文件)

    <!-- 可通过Mybatis观看详细说明--> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

    eviction可用的清除策略有:

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

    flushInterval(刷新间隔)属性可以被设置为任意的正整数

    size(引用数目)属性可以被设置为任意正整数

    readOnly(只读)属性可以被设置为 true 或 false

    自定义二级缓存

    条件:使用第三方缓存实现–EhCache:

    步骤

    1、导入依赖包

    <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version> </dependency>

    2、在SQL映射文件中填加

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

    3、编写ehcache.xml文件

    <?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <!-- diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下: user.home – 用户主目录 user.dir – 用户当前工作目录 java.io.tmpdir – 默认临时文件路径 --> <diskStore path="./tmpdir/Tmp_EhCache"/> <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="259200" memoryStoreEvictionPolicy="LRU"/> <cache name="cloud_user" eternal="false" maxElementsInMemory="5000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="1800" memoryStoreEvictionPolicy="LRU"/> <!-- defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。 --> <!-- name:缓存名称。 maxElementsInMemory:缓存最大数目 maxElementsOnDisk:硬盘最大缓存个数。 eternal:对象是否永久有效,一但设置了,timeout将不起作用。 overflowToDisk:是否保存到磁盘,当系统当机时 timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 clearOnFlush:内存数量最大时是否清除。 memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。 FIFO,first in first out,这个是大家最熟的,先进先出。 LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。 LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。 --> </ehcache>

    mybatis偷懒点

    改造MybatisUtils工具类的getSession( ) 方法,重载实现。

    //获取SqlSession连接 public static SqlSession getSession(){ return getSession(true); //事务自动提交 } public static SqlSession getSession(boolean flag){ return sqlSessionFactory.openSession(flag); } overflowToDisk:是否保存到磁盘,当系统当机时 timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 clearOnFlush:内存数量最大时是否清除。 memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。 FIFO,first in first out,这个是大家最熟的,先进先出。 LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。 LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

    –>

    ```

    mybatis偷懒点

    改造MybatisUtils工具类的getSession( ) 方法,重载实现。

    //获取SqlSession连接 public static SqlSession getSession(){ return getSession(true); //事务自动提交 } public static SqlSession getSession(boolean flag){ return sqlSessionFactory.openSession(flag); }

    【注意】确保实体类和数据库字段对应

    Processed: 0.020, SQL: 8