• MyBatis


    一、  MyBatis

    1.  什么是框架?

    1. 框架( Framework )是构成一类特定软件可复用设计的一组相互协作的类
    a.框架规定了你的应用的体系结构
    b.它定义了整体结构,类和对象的分割,各部分的主要责任,类和对象怎么协作,以及控制流程
    c.框架预定义了这些设计参数,以便于应用设计者或实现者能集中精力于应用本身的特定细节

    2. 框架、设计模式这两个概念总容易被混淆,其实它们之间还是有区别的
    a.构件通常是代码重用
    b.设计模式是设计重用
    c.框架则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用

    3. 在软件开发中有三种级别的重用:
    a.内部重用,即在同一应用中能公共使用的抽象块
    b.代码重用,即将通用模块组合成库或工具集,以便在多个应用和领域都能使用
    c.应用框架的重用,即为专用领域提供通用的或现成的基础结构,以获得最高级别的重用性

    4. 使用框架的优势:
    a.领域内的软件结构一致性好,可以建立更加开放的系统
    b.大力度的重用使得平均开发费用降低,开发速度加快,开发人员减少,维护费用降低,而参数化框架使得适应性、灵活性增强
    c.有利于在一个项目内多人协同工作

    2.  MyBatis 简介

    * MyBatis:是开源免费框架,原名 iBatis,它是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
      1. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集,即:是对 JDBC 的封装
      2. MyBatis 可以对配置和原生 Map 使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录
      3. Mybatis 的功能架构可分为三层:
         1)API 接口层:提供给外部使用的接口 API,开发人员通过这些本地 API 来操纵数据库。接口层--接收到调用请求就会调用数据处理层来完成具体的数据处理
         2)数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作
         3)基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑
    
    * MyBatis 的优势
      1. 解除 sql 与程序代码的耦合:通过提供 DAL 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql 和代码的分离,提高了可维护性
      2. 提供 xml 标签,支持编写动态 sql
      3. 提供映射标签,支持对象与数据库的 orm 字段关系映射
      4. 提供对象关系映射标签,支持对象关系组建维护
    
    * MyBatis 的缺点
      1. 编写 SQL 语句时工作量很大,尤其是字段多、关联表多时,更是如此
      2. SQL 语句依赖于数据库,导致数据库移植性差,不能更换数据库
      3. 二级缓存机制不佳

    * MyBatis 环境搭建 1. 导入 jar,将 mybatis-x.x.x.jar 文件置于 classpath 中即可
    下载地址:https://mvnrepository.com/artifact/org.mybatis/mybatis 2. 在 src 下新建 MyBatis 的配置文件:mybatis.xml。MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(settings)和属性(properties)信息 3. 新建以 Mapper 结尾的包,在包下新建 MyBatis XML 映射文件:实体类名 + Mapper.xml

    3.  MyBatis 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>
      <!-- 开启 Log4J 日志 -->
      <settings>
         <setting name="logImpl" value="LOG4J"/>
      </settings>
      
      <!-- 给某个类/某个包下所有类起别名。类型别名是为 Java 类型设置一个短的名字,它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余 -->
      <typeAliases>
         <typeAlias type="com.ncdx.pojo.Flower" alias="flower"/>
         <!-- 指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean。在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名 -->
         <package name="com.ncdx.pojo"/>
      </typeAliases>
    
      <environments default="default">
         <environment id="default">
            <transactionManager type="JDBC"></transactionManager>
            <!-- JDBC:这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围
                 MANAGED:把事务管理转交给其它容器。这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。如:
                 <transactionManager type="MANAGED"> 
                    <property name="closeConnection" value="false"/> 
                 </transactionManager> -->
             
            <!-- dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源 -->
            <dataSource type="POOLED">
            <!-- POOLED:使用数据连接池
                 UNPOOLED:不使用数据连接池,和直接使用 JDBC 一样
                 JNDI:Java 命名目录接口技术 -->
                    
              <property name="driver" value="com.mysql.jdbc.Driver"/>
              <property name="url" value="jdbc:mysql://localhost:3306/wollo?characterEncoding=utf-8"/>
              <property name="username" value="root"/>
              <property name="password" value="hello"/>
            </dataSource>
         </environment>
      </environments>
    
      <!-- 映射器(Mappers):这些配置会告诉 MyBatis 去哪里找映射文件 -->
      <mappers>
        <!-- 你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等 -->
        <mapper resource="com/ncdx/mapper/FlowerMapper.xml"/>
        <mapper url="file:///var/mappers/FlowerMapper.xml"/>
        <mapper class="com.ncdx.mapper.FlowerMapper.xml"/>
        <package name="com.ncdx.mapper" />
      </mappers>
      
    </configuration>
    mybatis.xml

    4.  Mapper.xml

    1. MyBatis 的真正强大在于它的映射语句,也是它的魔力所在,由于它的异常强大,映射器的 XML 文件就显得相对简单
    2. SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
       1)cache – 给定命名空间的缓存配置
       2)cache-ref – 其他命名空间缓存配置的引用
       3)resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象
       4)sql – 可被其他语句引用的可重用语句块
       5)insert – 映射插入语句
       6)update – 映射更新语句
       7)delete – 映射删除语句
       8)select – 映射查询语句
    3. MyBatis 的 Auto Mapping 特性:当自动匹配结果的时候,Mybatis 会获取表的列名,并且在对应 Java Bean 中找到一个与列名相同的属性(忽略大小写)。这意味着命名为 ID 的列和命名为 id 的属性被查找到的时候,Mybatis 将会把列 ID 的值赋给属性 id
    1)如:在 Mapper.xml 中
    <select id="selectUsers" resultType="User">
      select id, username, hashedPassword
      from some_table
      where id = #{id}
    </select>
    定义一个 Java Bean 如下
      public class User {
          private int id;
          private String username;
          private String hashedPassword;
    .... }
    上面这个类有 3 个属性:id,username 和 hashedPassword。这些 在 select 语句中会精确匹配到列名。如果列名没有精确匹配,你可以在列名上使用 select 字句的别名来匹配标签,如:
    <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>

    4. Select 属性

    1)id :在命名空间中唯一的标识符,可以被用来引用这条语句。id 值必须和接口中定义的方法名相同 2)parameterType = "dataType" :将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset 2.1)SqlSession 的 selectList()selectOne()的第个参数,selectMap()的第个参数都表示传入参数,如: People p = session.selectone("com.ncdx.Mapper.Flower.selById", 1); 2.2可以通过 #{int} 获取传入参数内容,注意下标从 0 开始,#{0} 等同于 #{param1} 获取第一个传入参数,如: <select id="selAll" resultType="com.ncdx.pojo.Flower" parameterType="int"> select * from flower where id = #{0} </select> a.如果传入参数是对象可以写成 #{属性名},注意属性名一定要有 getter/setter 方法 b.如果传入参数是 Map 类型,则写成 #{key}
    c.默认情况下,使用 #{} 格式的语法会导致 MyBatis 创建预处理语句属性并安全地设置值(使用 ? 占位符)。这样做更安全,更迅速,通常也是首选做法,不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用:ORDER BY ${columnName}这里 MyBatis 不会修改或转义字符串。注意以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的(不使用 ? 占位符),会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验
    2.3)如果接口中定义的方法中有多个参数,可以省略 parameterType
    3)resultType = "dataType" :从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用 3.1)如果方法返回值是 List,在 resultType 中写法:List<泛型>
    4)resultMap = "resultMapId":外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用
    5)useCache :将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true

    5. Insert, Update 和 Delete 的属性
    1)id :在命名空间中唯一的标识符,可以被用来引用这条语句。id 值必须和接口中定义的方法名相同
    2)parameterType = "dataType" :将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset
    3)useGeneratedKeys :仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。

    6. 多参数传递实现方法:
    1)在 #{} 中使用0,1,2 或者使用 param1,param2,param3,如:
    在接口中声明方法:List<Users> selByIdAndName(String uid, String uname);
    则在对应的 mapper.xml 中添加:
    <select id="selByIdAndName" resultType="users">
    select * from _users where uid=#{0/param1} and uname=#{1/param2}
    </select>

    2)使用注解:@Param()。使用注解后,MyBatis会用 Map 封装参数内容,如:
    在接口中声明方法:List<Users> selByIdAndName(@Param("id")String uid, @Param("name")String uname);
    则在对应的 mapper.xml 中添加:
    <select id="selByIdAndName" resultType="users">
     select * from _users where uid=#{id} and uname=#{name}
    </select>
    <?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 namespace="com.ncdx.mapper.FlowerMapper">
    
    <!-- 分页查询 -->
    <select id="selByPage" resultType="com.ncdx.pojo.People" parameterType="map" >
      select * from people limit #{pageStart},#{pageSize}
    </select>
    <select id="selCount" resultType="int">
      select count(*) from people
    </select>
    
    <insert id="insertAuthor">
      insert into Author (id,username,password,email,bio)
      values (#{id},#{username},#{password},#{email},#{bio})
    </insert>
    
    <update id="updateAuthor">
      update Author set
        username = #{username},
        password = #{password},
        email = #{email},
        bio = #{bio}
      where id = #{id}
    </update>
    
    <delete id="deleteAuthor">
      delete from Author where id = #{id}
    </delete>
    
    <!-- 如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就OK了。例如上面的 insert 语句可以写成: -->
    <insert id="insertAuthor" useGeneratedKeys="true"
        keyProperty="id">
      insert into Author (username,password,email,bio)
      values (#{username},#{password},#{email},#{bio})
    </insert>
    </mapper>
    Mapper.xml

    5.  MyBatis 动态 SQL

    1. MyBatis 的强大特性之一便是它的动态 SQL,所谓动态 SQL,就是根据不同的条件拼接 SQL 命令
    2. 如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦
    3. MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素
    4. 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似
    1)<if test="">...</if>

    2)<where>...</where>
    a.如果 <where> 里面有内容生成 where 关键字,没有就不生成
    b.消除无关的 and

    3)<choose>
    <when test="">...</when>
    <when test="">...</when>
    <otherwise>...</otherwise>
    </choose>

    4)<set>...</set>
    a.如果 <set> 里面有内容生成 set 关键字,没有就不生成
    b.消除无关的逗号
    c.如:
    <update id="upd" parameterType="log">
    update log
             <set>
    uid=#{id},// 目的是防止 <set> 中没有内容,Mybatis不生成 set 关键字,导致 SQL 语法错误而报错
    <if test="uname!=null and uname!=''">
                accin=#{name},
                 </if>
               </set>
               where uid=#{id}
      </update>

    5)<trim prefix/suffix="" prefixOverrides/suffixOverrides="" >...</trim>
    a.prefix:在前面添加指定内容
    b.prefixOverrides:去掉前缀指定内容
    c.suffix:在后面添加指定内容
    d.suffixOverrides:去掉后缀缀指定内容
    e.注意:一定是先去掉内容后添加内容

    6)<bind name="" value="" />
    a.作用:可以从 OGNL 表达式中创建一个变量并将其绑定到上下文
    b.模糊查询用得特别多,如:
            <select id="selUsersLike" resultType="users">
              <bind name="pattern" value="'%' + abc + '%'" />
              SELECT * FROM BLOG WHERE uname LIKE #{pattern}
            </select>

    7)<foreach item="item" index="index" collection="list" open="(" separator="," close=")">...</foreach>
    a.遍历参数内容,具备在内容的前后添加内容,还具备添加分隔符功能
    b.使用场景:in 查询,如:
          <select id="selectPostIn" resultType="domain.blog.Post">
            SELECT * FROM POST P WHERE ID in
            <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
              #{item}
            </foreach>
          </select>
    c.使用查询:批量新增,必须指定:factory.openSession(ExecutorType.BATCH);底层是 JDBC 的 Statement.addBatch();

    8)<sql id=""></sql> 和 <include refid=""></include>
    a.某些 SQL 片段如果希望复用,可以使用 <sql> 定义这个片段,如:
    <sql id="mysql">
        id,accin,accout,money
    </sql>
    <select id="sel">
    select <include refid="mysql"></include> from _users
    </select>

    6.  MyBatis 缓存

    1. 应用程序和数据库交互的过程是一个相对比较耗时的过程,缓存的意义是让应用程序减少对数据库的访问,提升程序运行效率
    2. MyBatis 默认情况下是开启了局部的 SqlSession 缓存
    a.同一个 SqlSession 对象调用同一个 <select> 时,只有在第一次时是访问数据库,然后把查询结果缓存到 SqlSession 缓存区中
    b.缓存的是 Statement 对象,在 Mybatis 中一个 <select> 对应一个 Statement 对象
    c.有效范围:必须是同一个 SqlSession 对象才能获取缓存数据

    3. 要开启二级缓存,即开启 SqlSessionFactory 缓存你需要在你的 SQL 映射文件中添加:<cache readOnly="true"/>
    a.如果不写 readOnly="true",需要把实体类序列化(把内存临时数据存储到硬盘中):实体类 implements Serializable
    b.有效范围:同一个 SqlSessionFactory 中的任何一个 SqlSession 对象都可以获取缓存数据
    c.使用时机:当数据频繁被使用,但很少被修改
    d.当 SqlSession 对象 close() 或 commit() 时会把 SqlSession 缓存的数据 flush 到 SqlSessionFactory 缓存区中

    7.  ResultMap 元素

    1. resultMap 是 MyBatis 中最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象
    2. resultMap 属性:
    1)id:在命名空间中唯一的标识符,可以被用来引用此结果映射
    2)type:一个完全合格的 Java 类名或类型别名
    3)autoMapping:如果存在,MyBatis 将启用或禁用此 ResultMap 的 Auto Mapping 特性。此属性覆盖全局 Auto Mapping 行为。默认值:unset
    3. resultMap 的子元素:
    1)<id property="属性名" column="列名"/>
    2)<result property="属性名" column="列名"/>
    a.id 和 result 都将一个单独列的值映射到简单数据类型(如:字符串、整型、双精度浮点数、日期等)的单独属性
    b.这两者之间的唯一不同是 id 表示的结果是标识属性(主键)。来帮助改进整体表现,特别是缓存和嵌入结果映射(也就是联合映射)
    3)<association property="对象的引用"
    select="另外一个映射语句的 ID"
    column="传递给另外一个映射语句的参数"
    javaType="对象类型"
    >
    </association>
    a.用于关联单个对象,例如:
    定义学生实体类
    public class Student {
        private int id;
        private String name;
        private int age;
         private int tid;
         private Teacher teacher;
    .... }
    定义老师实体类
    public class Teacher {
         private int id;
         private String name;
    private List<Student> list;
    .... }
    查询所有学生包含所属老师的信息
    <resultMap type="student" id="stuMap">
         <id column="id" property="id" />
         <result column="name" property="name" />
         <result column="age" property="age" />
         <result column="tid" property="tid" />
         <assosiation property="teacher"
    select="com.ncdx.mapper.TeacherMapper.selById" 
                   column="tid" >
         </association>
    </resultMap>
    <select id="selAll" resultMap="stuMap">
         select * from student
    </select>
    <select id="selById" parameterType="int" resultType="teacher">
         select * from teacher where id=#{0}
    </select>
    b.在使用时,如果列名和属性名相同可以不配置 <id> 和 <result>,使用 Auto Mapping 特性,但是 MyBatis 默认只会为每一列装配一次。即上面的 resultMap 也可以写为:
    <resultMap type="student" id="stuMap">
         <result column="tid" property="tid" /> // 这里 tid 需要装配两次,所以不能省略
         <assosiation property="teacher"
    select="com.ncdx.mapper.TeacherMapper.selById" 
                   column="tid" >
         </association>
    </resultMap>

    4)<collection property="集合的引用"
    select="另外一个映射语句的 ID"
    column="传递给另外一个映射语句的参数"
    ofType="集合对象的泛型"
    >
    </collection>
    a.用于装配对象的集合,例如:
    查询老师包含所带学生的信息
    <resultMap type="teacher" id="tmap">
         <id column="tid" property="id"/>
         <result column="tname" property="name" />
         <collection property="list" ofType="student">
               <id column="sid" property="id" />
               <result column="sname" property="name" />
               <result column="age" property="age" />
               <result column="tid" property="tid" />
         </collection>
    </resultMap>
    <select id="selAll" resultMap="tmap">
          select t.id   tid,   
                    t.name tname,
                    s.id   sid,
                    s.name  sname,
                    age,
                    tid
          from teacher t
          left join student s
          on t.id=s.tid
    </select>

    4. 由上可知,resultMap 关联对象、装配集合适用于多表查询,其实我们也可以通过使用 Auto Mapping 特性结合别名实现多表查询,需要注意的是:
    a.需要满足 Auto Mapping 的要求:列名和属性名相同
    b.只适用于查询关联单个对象的场景,如果是集合,要依靠 <resultMap><collection>
    c.SQL 中的关键字符,两侧添加反单引号,如:
    查询所有学生包含所属老师的信息
    <select id="selAll" resultType="student">
         select t.id `teacher.id`,
    t.name `teacher.name`,
    s.id id,
    s.name name,
    age,
    tid
         from student s
    left join teacher t
         on s.tid=t.id
    </select>

    8.  MyBatis 注解

    1. 注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销。MyBatis 的注解简化了 Mapper.xml 文件
    2. 如果涉及动态 SQL 依然使用 Mapper.xml
    3. Mapper.xml 和注解可以共存
    4. 使用注解时必须在 mybatis.xml 中配置映射器:<mappers>
    5. MyBatis 注解:
    1)@Select("select * from teacher")
    2)@Insert("insert into teacher value(default, #{name})")
    3)@Update("update teacher set name=#{name} where id=#{id}")
    4)@Delete("delete from teacher where id=#{0}")
    5)@Results(value={
         @Result(id=true, property="属性名", colum="列名"),
                  @Result(property="属性名", column="列名"),
    @Result(property="对象的引用", column="传递给另外一个映射语句的参数", one=@One(select="另外一个映射语句的 ID")),
                  @Result(property="集合的引用", column="传递给另外一个映射语句的参数", many=@Many(select="另外一个映射语句的 ID"))
          })
    a.@Results() 相当于 <resultMap>
    b.@Result() 相当于 <id /> 或 <result />
    c.@Result(id=true) 相当于 <id />
    d.@One() 相当于 <association>
      e.@Many() 相当于 <collection>

    6)@Param("id")String uid

    9.  MyBatis Java API

    1. 既然你已经知道如何配置 MyBatis 和创建映射文件,那么 MyBatis 的 Java API 就是你收获你所做的努力的地方。正如你即将看到的,和 JDBC 相比,MyBatis 很大程度简化了你的代码而且保持简洁,很容易理解和维护
    2. 在此之前让我们先了解一些必要的概念:
    1)功能:从应用程序角度出发,软件要具备哪些功能
    2)业务:完成功能的逻辑,对应 Service 中的一个方法
    3)事务:从数据库角度出发,完成业务时需要执行的 SQL 集合,统称一个事务
    4)事务回滚:如果在一个事务中某个 SQL 执行失败,希望回归到事务的原点,从而保证数据库数据的完整性

    2. SqlSessions 是使用 MyBatis 的主要 Java 接口。你可以使用这个接口执行命令、获取映射器和管理事务
    1)SqlSessions 是由 SqlSessionFactory 实例创建的,SqlSessionFactory 对象包含创建 SqlSession 实例的所有方法
    2)SqlSessionFactory 本身是由 SqlSessionFactoryBuilder 创建的,它可以从 XML 配置、注解或手动配置 Java 来创建 SqlSessionFactory

    3. InputStream is = Resources.getResourceAsStream("/mybatis.xml"); // 注意这里我们使用了 Resources 工具类,这个类在 org.mybatis.io 包中。Resources 类会帮助你从类路径下加载资源文件
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(InputStream is); // 使用 SqlSessionFactoryBuilder 创建 SqlSessionFactory 实例的最常用的方法

    4. SqlSession session = factory.openSession(); // 创建 SqlSession 实例。默认的 openSession() 方法没有参数,它会创建有如下特性的 SqlSession:
    1)会开启一个事务(也就是不自动提交)。设为自动提交:factory.openSession(true);
    2)连接对象会从由活动环境配置的数据源实例中得到。自定义连接对象:factory.openSession(Connection connection);
    3)事务隔离级别将会使用驱动或数据源的默认设置。不使用默认事务隔离级别设置:factory.openSession(TransactionIsolationLevel level);
    a.MyBatis 为事务隔离级别调用使用一个 Java 枚举包装器, 称为 TransactionIsolationLevel
    b.TransactionIsolationLevel 具有 JDBC 支持的 5 级 ( NONE、READ_UNCOMMITTED、READ_COMMITTED、REPEA TABLE_READ、SERIALIZA BLE )
    4)预处理语句不会被复用,也不会批量处理更新。
    a.批量新增需要指定:factory.openSession(ExecutorType.BATCH);
    b.复用预处理语句:factory.openSession(ExecutorType.REUSE);

    5. SqlSession 实例在 MyBatis 中是非常强大的一个类,你会在这里发现所有执行语句的方法,提交或回滚事务,还有获取映射器实例
    1)语句执行方法:这些方法被用来执行定义在 SQL 映射的 XML 文件中的增删改查语句。Object parameter 传入参数可选
    T selectOne(String statement, Object parameter);
    List selectList(String statement, Object parameter);
    Map selectMap(String statement, Object parameter, String mapKey);
    int insert(String statement, Object parameter);
    int update(String statement, Object parameter);
    int delete(String statement, Object parameter);

    2)事务控制方法:如果你已经选择了自动提交或你正在使用外部事务管理器,这就没有任何效果了。然而,如果你正在使用 JDBC 事务管理员,由 Connection 实例来控制,那么这四个方法就会派上用场
    void commit();
      void commit(boolean force);
        void rollback();
        void rollback(boolean force);

    3)清理 Session 级的缓存:void clearCache();
    4)确保 SqlSession 被关闭:void close();

    6. MyBatis 运行原理如图所示:
      运行过程中涉及到的类
       1)Resources
         作用:加载配置文件
    2)SqlSessionFactoryBuilder
       作用:创建 SqlSessionFactoryBuilder 实例
      3)XMLConfigBuilder
    作用:负责读取配置文件流并转换为 Java 代码
      4)Configuration
          a.作用:全局配置文件内容存放在 Configuration 中
    b.注意:在 SqlSessionFactory 中还有一个方法我们没有提及,就是 factory.getConfiguration(); 这个方法会返回一个 Configuration 实例,在运行时你可以使用它来自检 MyBatis 的配置
      5)DefaultSqlSessionFactory 是 SqlSessionFactory 的实例
      6)Transaction 事务
         作用:每一个 SqlSession 会带有一个 Transaction 对象
      7)TransactionFactory 事务工厂
          作用:负责生产 Transaction
      8)Executor 执行器
    a.作用:负责执行 SQL 命令
          b.相当于 JDBC 中的 Statement 对象(或 PreparedStatement 对象或 CallableStatement 对象)
          c.通过 factory.openSession(ExecutorType);指定执行器
    d.ExecutorType.SIMPLE:这个执行器类型不做特殊的事情(默认执行器)
    e.ExecutorType.REUSE:这个执行器类型会复用预处理语句
    f.ExecutorType.BATCH:这个执行器会批量执行所有更新语句
       9)DefaultSqlSession 是 SqlSession 的实例
       10)ExceptionFactory MyBatis 异常工厂

    10.  MyBatisUtil

    /**
     *  Threadlocal
     *  1. 线程容器,给线程绑定一个 Object 内容后只要线程不变,可以随时取出
     *     1.1.改变线程就无法取出内容 
     *  2. 语法示例:
     *     public static void main(String[] args) {
     *         final ThreadLocal<String> threadLocal = new ThreadLocal<>();
     *         threadLocal.set("测试");
     *         new Thread(){
     *             public void run(){
     *                    String result = threadLocal.get();
     *                    System.out.println("结果:"+result);
     *              }
     *         }.start();
     *    }
     */
    import java.io.IOException;
    import java.io.InputStream;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    public class MyBatisUtil {
        //factory 实例化的过程是一个比较耗费性能的过程
        //保证有且只有一个 factory
        private static SqlSessionFactory factory;
        private static ThreadLocal<SqlSession> tl = new ThreadLocal<>();
        static{
            try {
                InputStream is = Resources.getResourceAsStream("mybatis.xml");
                factory = new SqlSessionFactoryBuilder().build(is);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        public static SqlSession getSession(){
            SqlSession session = tl.get();
            if(session==null){
                tl.set(factory.openSession());
            }
            return tl.get();
        }
        
        public static void closeSession(){
            SqlSession session  = tl.get();
            if(session!=null){
                session.close();
            }
            tl.set(null);
        }
    }
    MyBatisUtil.java

    11.  Log4j

    1. Mybatis 内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:
       1)SLF4J
       2)Apache Commons Logging
       3)Log4j 2
       4)Log4j
       5)JDK logging

    2. 为什么需要日志?在项目中编写 System.out.prinln();输出到控制台,当项目部署到 Tomcat 后,没有控制台(在命令界面能看见),不容易观察一些输出结果。使用日志不仅能把内容输出到控制台,还能把内容输出到文件中,便于观察运行结果
    3. Log4J:由 apache 推出的开源免费日志处理的类库
    4. 在 MyBatis 中使用 Log4J
    1)Log4J 下载地址:https://mvnrepository.com/artifact/log4j/log4j 需要将 log4j.jar 添加到
    WEB-INF/lib 目录
    2)在 src 下新建一个名称为 log4j.properties 的属性文件,配置如下:
    log4j.rootLogger = ERROR,CONSOLE,LOGFILE
    log4j.logger.com.ncdx.mapper = INFO // 包级别:对 mapper 接口所在的包开启日志功能;类级别:log4j.logger.com.ncdx.mapper.FlowerMapper = INFO;方法级别:log4j.logger.com.ncdx.mapper.FlowerMapper.selAll = INFO
    #CONSOLE
    log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.Target = System.out
    log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
    #LOGFILE
    log4j.appender.LOGFILE = org.apache.log4j.FileAppender
    log4j.appender.LOGFILE.File = E://logs/log.log
    log4j.appender.LOGFILE.Append = true
    log4j.appender.LOGFILE.Threshold = DEBUG
    log4j.appender.LOGFILE.layout = org.apache.log4j.PatternLayout
    log4j.appender.LOGFILE.layout.ConversionPattern = %m %n
    3)在 mybatis.xml 中开启 log4j:
    <settings>
    <setting name="logImpl" value="LOG4J"/>
    </settings>

    5. Log4J 输出级别:fatal(致命错误) > error(错误) > warm(警告) > info(普通信息) > debug(调试信息)
    1)设置全局输出级别:log4j.rootLogger = ERROR
    2)设置某个指定位置的输出级别:log4j.logger.com.ncdx.mapper = DEBUG
    3)先设置全局输出级别为 ERROR,再设置某个指定位置的输出级别,可以防止输出无用信息
    4)log4j.appender.LOGFILE.File = E://logs/log.log :输出日志位置及名称(日志扩展名 *.log)

    6. Pattern 中常用的几个表达式
    1)%C  包名+类名
    2)%d{YYYY-MM-dd HH:mm:ss}  时间
    3)%L  行号
    4)%m  信息
    5)%n  换行
    6)%p  代表输出该条日志的等级,log4j.rootLogger = INFO, 这句中的 INFO 表示输出 INFO 级别及以上的日志。就是说:INFO,WARN,ERROR,FATAL 等消息都会输出。那每条日志到底是哪个级别呢?%p 就是输出每条日志对应的级别
  • 相关阅读:
    一个例子讲明爬虫请求库requests
    SpringBoot【六】 Shiro
    SpringBoot【五】 Spring Security
    SpringBoot【四】 任务
    Swagger
    SpringBoot【三】 整合 JDBC、Druid、MyBatis
    SpringBoot【二】 SpringBoot 配置
    SpringBoot【一】入门程序及原理分析
    SpingBoot 相关问题:启动 web 项目之后出现 java.lang.UnsatisfiedLinkError: D:Tomcatapache-tomcat-9.0.36in cnative-1.dll
    SpringBoot 相关问题:IDEA 创建 SpringBoot 项目时出现 Initialization failed for 'https://start.spring.io' 问题
  • 原文地址:https://www.cnblogs.com/IT-LFP/p/11199485.html
Copyright © 2020-2023  润新知