Mybatis笔记整理

1. 相关文档地址

  • 中文文档 https://mybatis.org/mybatis-3/zh/index.html
  • Mybatis可以配置成适应多种环境,不过每个SqlSessionFactory实例只能选择一种环境。
  • Mybatis默认事务管理器是JDBC,连接池:POOLED
  • Maven仓库:下载地址
<dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis</artifactId>
     <version>3.5.2</version>
 </dependency>

2. demo

新建普通maven项目作为父项目,导入sql驱动,mybatis,junit组件

  <!--导入依赖-->
  <dependencies>
      <!--mysql驱动-->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.46</version>
      </dependency>
      <!--Mybatis-->
      <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.2</version>
      </dependency>
      <!--junit-->
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
      </dependency>
  </dependencies>

新建新组件作为子级项目,普通maven的module
添加配置文件:
在src->main->resources目录下新建mybatis-config.xml文件,把官方的配置代码复制粘贴(不能在配置文件中写中文注释)

  <?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">
      <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
          <property name="driver" value="${driver}"/>//数据库驱动,不同驱动可连接不同数据库服务器
          <property name="url" value="${url}"/>//连接数据库的目录
          <property name="username" value="${username}"/>//数据库名字,默认root
          <property name="password" value="${password}"/>//数据库密码,自己的数据库密码,一般为root
        </dataSource>
      </environment>
    </environments>
  </configuration>

编写mybatis工具类

  //SqlSessionFactory --生产--> SqlSession
  public class MybatisUtils {
    
    
      private static SqlSessionFactory sqlSessionFactory; //提升作用域
      //获取工厂,固定代码
      static {
    
    
          try {
    
    
              String resource="mybatis-config.xml";
              InputStream inputStream = Resources.getResourceAsStream(resource);
              sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
          } catch (IOException e) {
    
    
              e.printStackTrace();
          }
      }
      //获取sqlSession
      //SqlSession完全包含了面向对象数据库执行SQL命令所需的方法
      public static SqlSession getSqlSession(){
    
     return sqlSessionFactory.openSession();}
  }

实体类

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 + '\'' +
                '}';
    }
}

Dao接口

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

接口实现类改为以xxxMapper.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">
  <!--namespace:命名空间,绑定mapper/Dao接口-->
  <mapper namespace="com.qian.dao.UserDao">
  <!--id:接口的方法,resultType:接口的返回值类型-->
      <select id="getUserList" resultType="com.qian.pojo.User">
          select * from mybatis.user where id = #{id}
      </select>
  </mapper>

测试类

  public class UserDaoTest {
    
    
      @Test
      public void test(){
    
    
          //获取SqlSession对象
          SqlSession sqlSession = MybatisUtils.getSqlSession();
          //获取mapper
          UserDao mapper = sqlSession.getMapper(UserDao.class);
          List<User> list = mapper.getUserList();
          for (User u:list){
    
    
              System.out.println(u);
          }
          //不推荐使用
  /*
      这种方式能够正常工作,对使用旧版本 MyBatis 的用户来说也比较熟悉。但现在有了一种更简洁的方式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。
  */
  //        List<User> list = sqlSession.selectList("com.qian.dao.UserDao.getUserList");
  //        for (User user : list) {
    
    
  //            System.out.println(user);
  //        }
          //关闭SqlSession
          sqlSession.close();
      }
  }

异常1:org.apache.ibatis.binding.BindingException: Type interface com.qian.dao.UserDao is not known to the MapperRegistry.
解决方法:每一个Mapper.xml文件都需要在src->main->resources目录下新建mybatis-config.xml的核心配置文件中注册

<mappers>
  <mapper resource="com/qian/dao/UserMapper.xml">
</mappers>

异常2:
Error building SqlSession.
The error may exist in com/qian/dao/UserMapper.xml
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration.
Cause: java.io.IOException: Could not find resource com/qian/dao/UserMapper.xml
解决方法:

<!-- 在maven中,约定大于配置,在pom中添加此文件可以解决 -->
<build>
  <resources>
      <resource>
          <directory>src/main/resources</directory>
          <includes>
              <include>**/*.properties</include>
              <include>**/*.xml</include>
          </includes>
          <filtering>true</filtering>
      </resource>
      <resource>
          <directory>src/main/java</directory>
          <includes>
              <include>**/*.properties</include>
              <include>**/*.xml</include>
          </includes>
          <filtering>true</filtering>
      </resource>
  </resources>
</build>

异常3:
Error building SqlSession.
The error may exist in com/qian/dao/UserMapper.xml
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration.
Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 6;
解决方法:

<?xml version="1.0" encoding="UTF-8" ?>    
<!-- 把mybatis-config.xml与mybatis-config.xml文件的encoding修改成下面的 -->
<?xml version="1.0" encoding="UTF8" ?>

异常4:
Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
解决方法:
useSSL=true改为false(true也可以,需要在mysql中启用SSL

<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8&amp;serverTimezone=GMT%2B8"/>

参考文档 :https://www.kuangstudy.com/bbs/1580393245333508097

3.配置文件优先级

  • 如果两个文件有同一个字段,优先使用外部配置文件
配置db.properties
      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&;useUnicode=true&;
      characterEncoding=UTF8&;serverTimezone=GMT%2B8&;autoConnect=true
      username=root
      password=root
在核心配置文件中引入
注意:在xml中,所有的标签都可以规定顺序
      (properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".

核心文件配置
      <configuration>
          <properties resource="db.properties"/>
          <environments default="development">
              <environment id="development">
                  <transactionManager type="JDBC"></transactionManager>
                  <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>
      </configuration>
总结
    可以直接引入外部文件
    也可以在<property></property>里面配置
    外部引入的文件(db.properties)的优先级要比在<property></property>要高
错误提示

4. LOG4J

Log4j是一个由Java编写可靠、灵活的日志框架,是Apache旗下的一个开源项目;现如今,Log4j已经被移植到了C、C++、Python等语言中,服务更多的Developer;`

      #newhappy  log4j.properties start
      log4j.rootLogger=DEBUG,console,file
      #控制台输出 console appender
      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
      #文件输出 rolling file appender
      log4j.appender.file=org.apache.log4j.RollingFileAppender
      log4j.appender.file.File=./log/yu.log
      log4j.appender.file.MaxFileSize=10mB
      log4j.appender.file.MaxBackupIndex=2
      log4j.appender.file.layout=org.apache.log4j.PatternLayout
      log4j.appender.file.layout.ConversionPattern=%d{mmm d,yyyy hh:mm:ss a} : %p [%t] %m%n
      log4j.appender.file.threshold=DEBUG
      #日志输出级别 logger
      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
      #newhappy log4j.properties end

解决方法:配置maven导入log4j

pom.xml
      <!-- https://mvnrepository.com/artifact/log4j/log4j -->
      <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
      </dependency>

5. MyBatis执行流程

  1. Resource获取加载全局配置文件
  2. 实例化SqlSessionFactoryBuilder构造器
  3. 解析配置文件流XMLConfigBuilder
  4. Configuration所有的配置信息
  5. SqlSessionFactory实例化
  6. transaction事务管理器
  7. 创建executor执行器
  8. 创建sqlSession
  9. 实现CRUD
  10. 查看是否执行成功
  11. 提交事务
  12. 关闭sqlSession连接
  • 注意:#{} 和KaTeX parse error: Expected 'EOF', got '#' at position 7: {} 注意:#̲{} 和{}
  • 1.#{} 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符;而${}仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。
  • 2.#{} 解析之后会将String类型的数据自动加上引号,其他数据类型不会;而${} 解析之后是什么就是什么,他不会当做字符串处理。
  • 3#{} 很大程度上可以防止SQL注入(SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作);而${} 主要用于SQL拼接的时候,有很大的SQL注入隐患。
  • 4.在某些特殊场合下只能用${},不能用#{}。例如:在使用排序时ORDER BY ${id},如果使用#{id},则会被解析成ORDER BY “id”,这显然是一种错误的写法。

6. Lombok

左上角File->Settings->Plugins
搜索Lombok,下载安装
导入maven
     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.18.10</version>
     </dependency>

Lombok的支持
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)
常用支持
@Data支持: 无参构造,getter&setter,toString,hashCode,equals
@AllArgsConstructor: 有参构造
@NoArgsConstructor: 无参构造
使用方法,在实体类上加注解

配置
  1. 关联 association 多对一
  2. 集合 collection 一对多
  3. javaType 指定实体类中属性的类型
  4. ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

7.缓存

  1. 什么是缓存(Cache)

    每次查询都要连接数据库,比较耗资源,我们把查询到的数据暂存到内存里面,下次查询的时候,从内存读取, 这个地方就叫缓存。

    存在内存中的临时数据

    将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询、从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题

  2. 为什么要使用缓存

    减少和数据库的交互次数,减小系统开销,提高系统效率

  3. 什么样的数据适用于缓存?

    经常查询且不经常改变的数据

  • Mybatis缓存
  1. Mybatis系统默认定义了两级缓存
  2. 默认情况下,只有一级缓存开启(SqlSession缓存,也称为本地缓存)
  3. 二级缓存需要手动配置,它是基于namespace级别的缓存
  4. Mybatis定义了缓存接口Cache,可以通过实现Cache接口来自定义二级缓存

二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个命名空间,对应一个二级缓存
  • 工作机制
    1.一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    2.如果当前会话关闭了,这个会话对应的一级缓存就没了,但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    3.新的会话查询信息,就可以从二级缓存中获取内容;
    4.新的会话查询信息,就可以从二级缓存中获取内容;
    5.不同的mapper查出的数据会放在自己对应的缓存(map)中;
  • 也就是说一级缓存死的时候,把数据交给了二级缓存

提示:缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。

这些属性可以通过 cache 元素的属性来修改。比如:

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

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

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

*** 默认的清除策略是 LRU。***

源文档: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

<settings>
    <!-- 标准的日志工厂实现-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <!-- 显示开启全局缓存-->
	<setting name="cacheEnabled" value="true"/>
</settings>

然后Mapper中添加 <cache>可以带上上面的参数

原理

在这里插入图片描述

8.EhCache

  1. EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。

  2. 导包

    <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
            <dependency>
             <groupId>org.mybatis.caches</groupId>
             <artifactId>mybatis-ehcache</artifactId>
             <version>1.2.2</version>
            </dependency>
    
  3. 写入配置文件(resources->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 path="java.io.tmpdir/ehcache"/>
            <!-- 默认缓存 -->
            <defaultCache
                   maxEntriesLocalHeap="10000"
                   eternal="false"
                   timeToIdleSeconds="120"
                   timeToLiveSeconds="120"
                   maxEntriesLocalDisk="10000000"
                   diskExpiryThreadIntervalSeconds="120"
                   memoryStoreEvictionPolicy="LRU">
             <persistence strategy="localTempSwap"/>
            </defaultCache>
            <!-- helloworld缓存 -->
            <cache name="HelloWorldCache"
                  maxElementsInMemory="1000"
                  eternal="false"
                  timeToIdleSeconds="5"
                  timeToLiveSeconds="5"
                  overflowToDisk="false"
                  memoryStoreEvictionPolicy="LRU"/>
            </ehcache>
    
  4. 在Mapper中指定

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

    在实际开发中,我们更多的使用Redis来做缓存

猜你喜欢

转载自blog.csdn.net/u013080870/article/details/129105657
今日推荐