栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis总结笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis总结笔记

文章目录
  • Mybatis 2021年8月30日
    • 一、简介
      • 什么是 MyBatis?
      • 获取mybatis
      • 持久化
        • 为什么要持久化?
      • 持久层
      • 为什么要使用mybatis?
    • 二、编写第一个mybatis程序
      • 搭建环境
          • maven pom.xml
          • usermapper接口
          • usermapper.xml
          • user
          • mybatis-config.xml
          • util 工具类
    • CURD
      • mapper.xml内容配置
        • 1、nameSpace
        • 2、select、insert、delete、update
      • 通过Map传递参数
      • 模糊查询
    • 三、配置解析
      • 1.核心配置文件
      • 2.环境配置
      • 3. 映射器(mappers)
      • 4.属性(properties)
      • 5. 类型别名(typeAliases)
      • 6. 设置(settings)
        • 7.其他配置
      • 8. 探究已映射的 SQL 语句
      • 9. 作用域(Scope)和生命周期
        • SqlSessionFactoryBuilder
        • SqlSessionFactory
        • SqlSession
    • 四、解决属性名和字段名不一致的问题
      • 问题
      • 解决方法
        • 1. 起别名
        • 2. resultMap
      • 结果映射
        • 高级结果映射
        • 结果映射(resultMap)
      • 字符串替换
    • 五、日志
      • 日志工厂
        • 使用STDOUT_LOGGING标准日志输出
      • 使用log4J
        • 第一步
        • 第二步 配置文件
        • 第三步 添加配置
        • 第四步 简单使用
      • log4J的一些配置信息
        • 控制台的一些信息
    • 六、分页
    • 七、注解开发
      • 关于@param()注解
    • 八、mybatis详细执行流程
    • 九、lombok
    • 十、多对一、一对多
      • 查询多对一
      • 一对多
    • 动态SQL
    • 1、if
    • 2、where
    • 3、choose(when、otherwise)
    • 4、tirm
    • 5、set
    • 6、foreach
    • 缓存
      • 简介
      • Mybatis缓存
        • 使用方法
        • 刷新缓存的情况
        • 缓存原理
        • 使用自定义缓存
          • 手写缓存
          • 第三方缓存
        • cache-ref

Mybatis 2021年8月30日 一、简介

什么是 MyBatis?
  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射。
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](https://baike.baidu.com/item/google code/2346604),并且改名为MyBatis 。
  • 2013年11月迁移到Github。
  • iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
  • 当前,最新版本是MyBatis 3.5.7 ,其发布时间是2021年4月21日。
获取mybatis
  • maven:Maven Repository: org.mybatis » mybatis (mvnrepository.com)

    •     
          
              org.mybatis
              mybatis
              3.5.7
          
      
  • GitHub:mybatis/mybatis-3: MyBatis SQL mapper framework for Java (github.com)

  • 中文文档:mybatis – MyBatis 3 | 简介

持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存: 断电即失
  • 数据库(JDBC),IO文件持久化
  • 生活:冷藏,罐头
为什么要持久化?
  • 有一些数据不想要丢失
  • 内存太贵了
持久层

Dao层,Service层,Controller层…

  • 完成持久化工作的代码块
  • 层界线十分明显
  • 持久化是一个过程,持久层是一个概念
为什么要使用mybatis?
  • 方便
  • 传统的JDBC代码十分复杂。简化、框架、自动化。
  • 不用mybatis也可以,更容易上手。技术没有高低之分
  • 优点
    • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
    • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。
    • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。
    • sql和代码的分离,提高了可维护性: sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql。
二、编写第一个mybatis程序 搭建环境

目录结构

maven pom.xml
  
        
            
            mysql
            mysql-connector-java
            8.0.23
        
        
        
        
            org.mybatis
            mybatis
            3.5.7
        
        
        
            junit
            junit
            4.13.2
            test
        
    
     
        
            
                src/main/java
                
                    ***.xml
                
                true
            
        
    
usermapper接口
package com.ziop.mapper;

import com.ziop.pojo.User;

import java.util.List;

public interface UserMapper {
    List getUserList();
}
usermapper.xml



    
        select * from mybatis.user;
    

1、nameSpace

namespace中的包名要和mapper接口的包名一致

2、select、insert、delete、update

选择查询语句;

  • id: 就是对应的namespace中的方法名
  • resultType: SQL语句执行的返回值! class,int等等
  • parameterType: 参数类型

案例

  • 接口中增加的查询方法
        User getUserById(int id);

mapper的xml中的SQL语句配置 ,其中的id 是值得user类的属性, 之所以我们可以直接用user而不需要添加全类名,是因为,我们之前在mybatis-confi.xml 中配置了[别名](# mybatis-config.xml)


    select * from Blog where id = #{id}
  

为了这个简单的例子,我们似乎写了不少配置,但其实并不多。

在一个 XML 映射文件中,可以定义无数个映射语句,这样一来,XML 头部和文档类型声明部分就显得微不足道了。

文档的其它部分很直白,容易理解。

  • 它在命名空间 “org.mybatis.example.BlogMapper” 中定义了一个名为 “selectBlog” 的映射语句,这样你就可以用全限定名 “org.mybatis.example.BlogMapper.selectBlog” 来调用映射语句了,就像上面例子中那样:
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);

你可能会注意到,这种方式和用全限定名调用 Java 对象的方法类似。

这样,该命名就可以直接映射到在命名空间中同名的映射器类,并将已映射的 select 语句匹配到对应名称、参数和返回类型的方法。

因此你就可以像上面那样,不费吹灰之力地在对应的映射器接口调用方法,就像下面这样:

BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);

第二种方法有很多优势,首先它不依赖于字符串字面值,会更安全一点;

其次,如果你的 IDE 有代码补全功能,那么代码补全可以帮你快速选择到映射好的 SQL 语句。


提示 对命名空间的一点补充

在之前版本的 MyBatis 中,**命名空间(Namespaces)**的作用并不大,是可选的。 但现在,随着命名空间越发重要,你必须指定命名空间。

​ 命名空间的作用有两个,一个是利用更长的全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定。就算你觉得暂时用不到接口绑定,你也应该遵循这里的规定,以防哪天你改变了主意。 长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。

**命名解析:**为了减少输入量,MyBatis 对所有具有名称的配置元素(包括语句,结果映射,缓存等)使用了如下的命名解析规则。

  • 全限定名(比如 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及使用。
  • 短名称(比如 “selectAllThings”)如果全局唯一也可以作为一个单独的引用。 如果不唯一,有两个或两个以上的相同名称(比如 “com.foo.selectAllThings” 和 “com.bar.selectAllThings”),那么使用时就会产生“短名称不唯一”的错误,这种情况下就必须使用全限定名。

9. 作用域(Scope)和生命周期

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。


提示 对象生命周期和依赖注入框架

  • 依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。

  • 如果对如何通过依赖注入框架使用 MyBatis 感兴趣,可以研究一下 MyBatis-Spring 或 MyBatis-Guice 两个子项目。


SqlSessionFactoryBuilder
  • 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。

  • 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

  • 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession
  • 每个线程都应该有它自己的 SqlSession 实例。
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。
  • 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。
  • 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。
  • 所以sqlsession每次使用之后都要关闭一下

四、解决属性名和字段名不一致的问题 问题

解决方法 1. 起别名
  •     
            select *
            from mybatis.user;
        
        
            
        
    

    映射的时候只需要写不一样的映射就行了

    结果映射

    resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

    之前你已经见过简单映射语句的示例,它们没有显式指定 resultMap。比如:

    
      select id, username, hashedPassword
      from some_table
      where id = #{id}
    
    

    类型别名是你的好帮手。使用它们,你就可以不用输入类的全限定名了。比如:

    
    
    
    
      select
        user_id             as "id",
        user_name           as "userName",
        hashed_password     as "hashedPassword"
      from some_table
      where id = #{id}
    
    

    在学习了上面的知识后,你会发现上面的例子没有一个需要显式配置 ResultMap,这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。 虽然上面的例子不用显式配置 ResultMap。 但为了讲解,我们来看看如果在刚刚的示例中,显式使用外部的 resultMap 会怎样,这也是解决列名不匹配的另外一种方式。

    
      
      
      
    
    

    然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:

    
      select
           B.id as blog_id,
           B.title as blog_title,
           B.author_id as blog_author_id,
           A.id as author_id,
           A.username as author_username,
           A.password as author_password,
           A.email as author_email,
           A.bio as author_bio,
           A.favourite_section as author_favourite_section,
           P.id as post_id,
           P.blog_id as post_blog_id,
           P.author_id as post_author_id,
           P.created_on as post_created_on,
           P.section as post_section,
           P.subject as post_subject,
           P.draft as draft,
           P.body as post_body,
           C.id as comment_id,
           C.post_id as comment_post_id,
           C.name as comment_name,
           C.comment as comment_text,
           T.id as tag_id,
           T.name as tag_name
      from Blog B
           left outer join Author A on B.author_id = A.id
           left outer join Post P on B.id = P.blog_id
           left outer join Comment C on P.id = C.post_id
           left outer join Post_Tag PT on PT.post_id = P.id
           left outer join Tag T on PT.tag_id = T.id
      where B.id = #{id}
    
    

    你可能想把它映射到一个智能的对象模型,这个对象表示了一篇博客,它由某位作者所写,有很多的博文,每篇博文有零或多条的评论和标签。 我们先来看看下面这个完整的例子,它是一个非常复杂的结果映射(假设作者,博客,博文,评论和标签都是类型别名)。 不用紧张,我们会一步一步地来说明。虽然它看起来令人望而生畏,但其实非常简单。

    
      
        
      
      
      
        
        
        
        
        
        
      
      
        
        
        
        
          
        
        
          
        
        
          
        
      
    
    

    resultMap 元素有很多子元素和一个值得深入探讨的结构。 下面是resultMap 元素的概念视图。

    结果映射(resultMap)
    • constructor用于在实例化类时,注入结果到构造方法中

      • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
      • arg - 将被注入到构造方法的一个普通结果
    • id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能

    • result – 注入到字段或 JavaBean 属性的普通结果

    • association
      
    • 一个复杂类型的关联;许多结果将包装成这种类型

      • 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
    • collection 一个复杂类型的集合

      • 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
    • discriminator 使用结果值来决定使用哪个resultMap

      • case– 基于某些值的结果映射
        • 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
    属性描述
    id当前命名空间中的一个唯一标识,用于标识一个结果映射。
    type类的完全限定名, 或者一个类型别名(关于内置的类型别名,可以参考上面的表格)。
    autoMapping如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。

    最佳实践

    • 最好逐步建立结果映射。

    • 单元测试可以在这个过程中起到很大帮助。

    • 如果你尝试一次性创建像上面示例那么巨大的结果映射,不仅容易出错,难度也会直线上升。 所以,从最简单的形态开始,逐步迭代。

    • 而且别忘了单元测试! 有时候,框架的行为像是一个黑盒子(无论是否开源)。因此,为了确保实现的行为与你的期望相一致,最好编写单元测试。

    • 并且单元测试在提交 bug 时也能起到很大的作用。

    字符串替换

    默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:

    ORDER BY ${columnName}
    

    这样,MyBatis 就不会修改或转义该字符串了。

    当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。 举个例子,如果你想 select 一个表任意一列的数据时,不需要这样写:

    @Select("select * from user where id = #{id}")
    User findById(@Param("id") long id);
    
    @Select("select * from user where name = #{name}")
    User findByName(@Param("name") String name);
    
    @Select("select * from user where email = #{email}")
    User findByEmail(@Param("email") String email);
    
    // 其它的 "findByXxx" 方法
    

    而是可以只写这样一个方法:

    @Select("select * from user where ${column} = #{value}")
    User findByColumn(@Param("column") String column, @Param("value") String value);
    

    其中 ${column} 会被直接替换,而 #{value} 会使用 ? 预处理。 这样,就能完成同样的任务:

    User userOfId1 = userMapper.findByColumn("id", 1L);
    User userOfNameKid = userMapper.findByColumn("name", "kid");
    User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");
    

    这种方式也同样适用于替换表名的情况。

    提示 用这种方式接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击。因此,要么不允许用户输入这些字段,要么自行转义并检验这些参数。

    五、日志 日志工厂

    如果一个数据库操作,出现了异常,我们需要排错,日志是最好的助手!

    曾经的,sout、debug

    现在的日志工厂!

    logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置
    • SLF4J
    • LOG4J 【掌握】
    • LOG4J2
    • JDK_LOGGING
    • COMMONS_LOGGING
    • STDOUT_LOGGING 【掌握】
    • NO_LOGGING

    在mybatis中具体使用一个日志实现,

     
            
        
    

    测试代码

        @Test
        public void getUserById() throws IOException {
            SqlSession session = SqlSessionUtil.getSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            User users = mapper.getUserById(1);
            System.out.println(users);
            session.close();
        }
    
    使用STDOUT_LOGGING标准日志输出
    Opening JDBC Connection
    Created connection 1190820921.
    ==>  Preparing: select * from mybatis.user where id = 1;
    ==> Parameters: 
    <==    Columns: id, name, password
    <==        Row: 1, 张三, 123456
    <==      Total: 1
    User{id=1, name='张三', password='123456'}
    Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@46fa7c39]
    Returned connection 1190820921 to pool.
    
    使用log4J
    • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件等;
    • 我们也可以控制每一条日志的输出格式;
    • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
    • 这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
    第一步

    加入log4j-1.2.8.jar(可以选择log4j的更高版本)到lib下。

    如果使用maven项目,也可以选择在pom.xml中新增依赖:

    
    
    
    log4j
    
    log4j
    
    1.2.17
    
    
    
    第二步 配置文件

    在CLASSPATH下建立log4j.properties。内容如下:

    # Global logging configuration
    # 设置日志输出级别以及输出目的地,可以设置多个输出目的地,开发环境下,日志级别要设置成DEBUG或者ERROR
    # 前面写日志级别,逗号后面写输出目的地:我自己下面设置的目的地相对应,以逗号分开
    # log4j.rootLogger = [level],appenderName1,appenderName2,…
    log4j.rootLogger=DEBUG,CONSOLE,LOGFILE
    
    #### 控制台输出 ####
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    # 输出到控制台
    log4j.appender.CONSOLE.Target = System.out
    # 指定控制台输出日志级别
    log4j.appender.CONSOLE.Threshold = DEBUG
    # 默认值是 true, 表示是否立即输出
    log4j.appender.CONSOLE.ImmediateFlush = true
    # 设置编码方式
    log4j.appender.CONSOLE.Encoding = UTF-8
    # 日志输出布局
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    # 如果日志输出布局为PatternLayout 自定义级别,需要使用ConversionPattern指定输出格式
    log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p (%c:%L) - %m%n
    
    
    
    #### 输出错误信息到文件 ####
    log4j.appender.LOGFILE=org.apache.log4j.FileAppender
    # 指定输出文件路径
    #log4j.appender.LOGFILE.File =F://Intellij idea/logs/error.log 
    log4j.appender.LOGFILE.File =./logs/error.log 
    
    #日志输出到文件,默认为true
    log4j.appender.LOGFILE.Append = true
    # 指定输出日志级别
    log4j.appender.LOGFILE.Threshold = ERROR
    # 是否立即输出,默认值是 true,
    log4j.appender.LOGFILE.ImmediateFlush = true
    # 设置编码方式
    log4j.appender.LOGFILE.Encoding = UTF-8
    # 日志输出布局
    log4j.appender.LOGFILE.layout = org.apache.log4j.PatternLayout
    # 如果日志输出布局为PatternLayout 自定义级别,需要使用ConversionPattern指定输出格式
    log4j.appender.LOGFILE.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    
    第三步 添加配置

    mybatis-config.xml

      
              
        
    
    第四步 简单使用

    在要输出日志的类中加入相关语句:

    定义属性:

    static Logger logger = Logger.getLogger(LogDemo.class); //LogDemo为相关的类
    

    在相应的方法中:

    if (logger.isDebugEnabled()){
    
    logger.debug(“System …..”);
    
    }
    

    测试类

    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.junit.Test;
    
    public class Log4jTest {
    
        //创建日志对象 Logger
        static final Logger logger = Logger.getLogger(Log4jTest.class);
    
        @Test
        public void testLog4j(){
    
            //显示警告级别以上的信息
            logger.setLevel(Level.WARN);
            // debug level
            logger.debug("DEBUG(调试)");
            // info level
            logger.info("INFO(消息)");
            // warning level
            logger.warn("WARN(警告)");
            // error level
            logger.error("ERROR(错误)");
        }
    
    }
    
    log4J的一些配置信息
    log4j.rootLogger = [ level ] , appenderName, appenderName, …
    

    2.配置日志信息输出目的地Appender,其语法为:

    log4j.appender.appenderName = fully.qualified.name.of.appender.class  
    log4j.appender.appenderName.option1 = value1  
    …  
    log4j.appender.appenderName.option = valueN
    

    其中,Log4j提供的appender有以下几种:

    org.apache.log4j.ConsoleAppender(控制台),  
    org.apache.log4j.FileAppender(文件),  
    org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),  
    org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),  
    org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
    

    例如:

    log4j.appender.ConSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.LOGFILE=org.apache.log4j.FileAppender
    

    3.配置日志信息的格式(布局),其语法为:

    log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class  
    log4j.appender.appenderName.layout.option1 = value1  
    …  
    log4j.appender.appenderName.layout.option = valueN
    

    其中,Log4j提供的layout有以e几种:

    org.apache.log4j.HTMLLayout(以HTML表格形式布局),  
    org.apache.log4j.PatternLayout(可以灵活地指定布局模式),  
    org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),  
    org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
    

    Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下: %m 输出代码中指定的消息

    %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL  
    %r 输出自应用启动到输出该log信息耗费的毫秒数  
    %c 输出所属的类目,通常就是所在类的全名  
    %t 输出产生该日志事件的线程名  
    %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”  
    %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921  
    %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
    
    控制台的一些信息
    Threshold=DEBUG:指定日志消息的输出最低层次。
    ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
    Target=System.err:默认情况下是:System.out,指定输出控制台
    FileAppender 选项
    Threshold=DEBUF:指定日志消息的输出最低层次。
    ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
    File=mylog.txt:指定消息输出到mylog.txt文件。
    Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
    RollingFileAppender 选项
    Threshold=DEBUG:指定日志消息的输出最低层次。
    ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
    File=mylog.txt:指定消息输出到mylog.txt文件。
    Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
    MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。
    MaxBackupIndex=2:指定可以产生的滚动文件的最大数。
    log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
    
    六、分页

    分页的目的

    • 减少查询的数据量

    使用limit语法

    select *
    from user
    limit 3,2;
    
    • 写接口

    • 注册mapper

      • 
            select *
            from mybatis.user
            limit #{startIndex},#{pageSize};
        
        
    • 测试

    使用RowBounds

    • 写接口

    • 注册mapper

      • 
                select *
                from mybatis.teacher
                where id = #{tid};
            
        
        

        方法二

         
                select s.id sid, s.name sname, t.id id, t.name tname
                from mybatis.teacher t,
                     mybatis.student s
                where t.id = #{tid}
                  and t.id = s.tid;
            
            
                
                
                
                    
                    
                    
                
            
        
            
            
                select *
                from mybatis.student
                where tid = #{tid};
            
        
        1. 关联 association 【多对一】

        2. 集合 collection 【一对多】

        3. javaType & ofType

          1. javaType 用来映射实体类中属性的类型
          2. ofType 用来映射到List 或者集合中的pojo类型,泛型中的约束类型

        注意点:

        • 保证SQL的可读性,尽量通俗易懂
        • 注意一对多和多对一中,属性和字段名的问题
        • 如果问题不好排查错误,可以使用日志,建议使用Log4J
        动态SQL

        概念: 动态SQL就是根据不同的条件生成不同的SQL

        如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

        • if
        • choose (when, otherwise)
        • trim (where, set)
        • foreach
        1、if
        
        	SELECT * FROM BLOG
        
        
          AND title like #{title}
        
          
          AND name like #{title}
        
         
        
        
        3、choose(when、otherwise)

        choose 相当于 java 里面的 switch 语句。otherwise(其他情况)

          
          select * from t_blog where id in  
           
              #{item}  
            
          
        

        open separator close

        相当于是in (?,?,?)

        如果是个map怎么办

          
        

        collection对应map的键,像这样

        List ids = new ArrayList();  
          ids.add(1);  
             ids.add(2);  
          ids.add(3);  
          ids.add(6);  
          ids.add(7);  
             ids.add(9);  
          Map params = new HashMap();  
          params.put("ids", ids);  
        
        缓存 简介

        查询 : 连接数据库,十分的耗费资源

        ​ 一次查询的结果,给她暂存在一个可以直接取到的地方! --> 内存 : 缓存

        我们再次查询相同的数据的时候, 直接走缓存就行,不用再走数据库

        缓存(cache),原始意义是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。缓存的设置是所有现代计算机系统发挥高性能的重要因素之一。

        读写分离,主从复制

        1. 什么是缓存 [ Cache ]?
          • 存在内存中的临时数据。
          • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
        2. 为什么使用缓存?
          • 减少和数据库的交互次数,减少系统开销,提高系统效率。
        3. 什么样的数据能使用缓存?
          • 经常查询并且不经常改变的数据。
        Mybatis缓存
        • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

        • MyBatis系统中默认定义了两级缓存:

          一级缓存

          二级缓存

          • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
          • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
          • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
          • 二级缓存的时候需要将实体类进行序列化 实现Serializable接口

        MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。

        使用方法

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

        
        

        在mybatis-config.xml中添加

        
             
         
        

        基本上就是这样。这个简单语句的效果如下:

        刷新缓存的情况
        • 映射语句文件中的所有 select 语句的结果将会被缓存。
        • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
        • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
        • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
        • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
        • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

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

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

        
        

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

        可用的清除策略有:

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

        默认的清除策略是 LRU。

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

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

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

        提示 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。

        缓存原理

        使用自定义缓存

        使用方法

        
        
        手写缓存

        除了上述自定义缓存的方式,你也可以通过实现你自己的缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。

        
        

        这个示例展示了如何使用一个自定义的缓存实现。type 属性指定的类必须实现 org.apache.ibatis.cache.Cache 接口,且提供一个接受 String 参数作为 id 的构造器。 这个接口是 MyBatis 框架中许多复杂的接口之一,但是行为却非常简单。

        public interface Cache {
        String getId();
        int getSize();
        void putObject(Object key, Object value);
        Object getObject(Object key);
        boolean hasKey(Object key);
        Object removeObject(Object key);
        void clear();
        }
        

        为了对你的缓存进行配置,只需要简单地在你的缓存实现中添加公有的 JavaBean 属性,然后通过 cache 元素传递属性值,例如,下面的例子将在你的缓存实现上调用一个名为 setCacheFile(String file) 的方法:

        
        
        
        

        你可以使用所有简单类型作为 JavaBean 属性的类型,MyBatis 会进行转换。 你也可以使用占位符(如 ${cache.file}),以便替换成在配置文件属性中定义的值。

        从版本 3.4.2 开始,MyBatis 已经支持在所有属性设置完毕之后,调用一个初始化方法。 如果想要使用这个特性,请在你的自定义缓存类里实现 org.apache.ibatis.builder.InitializingObject 接口。

        public interface InitializingObject {
        void initialize() throws Exception;
        }
        

        提示 上一节中对缓存的配置(如清除策略、可读或可读写等),不能应用于自定义缓存。

        请注意,缓存的配置和缓存实例会被绑定到 SQL 映射文件的命名空间中。 因此,同一命名空间中的所有语句和缓存将通过命名空间绑定在一起。 每条语句可以自定义与缓存交互的方式,或将它们完全排除于缓存之外,这可以通过在每条语句上使用两个简单属性来达成。 默认情况下,语句会这样来配置: