Mybatis:总体的学习笔记

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 行为的设置和属性信息。 配置文档的顶层结构如下:

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

环境配置

​ 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 通过使用内置的日志工厂提供日志功能

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK 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);
  }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值