学习第四天 --Mybatis学习总结

Mybatis

什么是Mybatis?

  • MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录

持久层

数据持久化

  • 实现程序的数据持久状态和瞬时状态之间的转换过程
  • 内存
  • 数据库

持久层

  • Dao层:完成持久化的操作,通过JDBC与数据库交互

Mybatis程序

  • db.properties
//数据库连接的必要配置
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/xjgl?useSSL=true&useUnicode=true&characterEncoding=utf-8
username = root
password = 123456
  • 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>
    <properties resource="db.properties"/>
    <!--可以配置多个环境但只可以选择使用一个环境-->
    <environments default="development">
        <environment id="development">
            <!--事务管理器:JDBC|MANAGED-->
            <transactionManager type="JDBC"/>
            <!--数据源:POOLED|UNPOOLED|JNDI-->
            <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>
    </environments>
    <!--映射器:用于mapper注册:指定对应的mapper.xml文件(相对文件路径:resource|接口类路径:class|全部的接口类:name)-->
    <mappers>
        <mapper resource="xyz/mintop/dao/ScoreMapper.xml"/>
    </mappers>
</configuration>
  • MybatisUtil
public class MybatisUtil {
    
    
    private static SqlSessionFactory sqlSessionFactory;
    static {
    
    
        try {
    
    
            //使用流获得mybatis-config.xml的配置信息
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //得到配置的SqlSessionFactoryBuilder()用于得到sqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    //获得SqlSession对象
    public static SqlSession getSqlSession(){
    
    
        return sqlSessionFactory.openSession();
    }
}
  • pojo类
//从数据库拿到的数据封装在实体类中(通过mapper.xml中的resultType|resultMap)
//注意:实体类需要进行序列化
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course {
    
    
    private String cid;
    private String cName;
    private String tid;
    private String classroom;
    private String course;
}
  • mapper接口类
//执行sql的方法
//与mapper.xml文件相关联,通过方法名和id一致
public interface ScoreMapper {
    
    
    List<Score> selectScore();//查询方法
    //@Param注解的使用,用于少量的参数
    List<Score> selectScoreById(@Param("id")String id);//条件查询方法
    void insertScore(Score score);//插入方法
    //使用Map传递参数,用于多个参数
    int upDataScore(Map<String,Object> map); //修改方法
}
  • mapper.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">
<mapper namespace="xyz.mintop.dao.ScoreMapper">
    <!--id与接口方法名一致-->
    <!--resultType:结果返回的类型(数据库列名和实体类变量名相同时)-->
    <!--resultMap:结果返回集合,经过resultMap处理,再封装到实体类(数据库列名和实体类变量名不完全相同时)-->
    <select id="selectScore" resultType="xyz.mintop.pojo.Score">
        select * from score
    </select>
    <!--parameterType:参数类型-->
    <select id="selectScoreById" parameterType="String" resultType="xyz.mintop.pojo.Score">
        select * from score where sid = #{id}
    </select>
    <insert id="insertScore" parameterType="xyz.mintop.pojo.Score">
        insert into score values (#{sid},#{cid},#{score})
    </insert>
    <update id="upDataScore" parameterType="map">
        update score set score = #{scores} where cid = #{cId}
    </update>
</mapper>
  • 测试类
@Test
public void test(){
    
    
    //获得sqlSession对象
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    //通过反射获得接口类对象
    ScoreMapper mapper = sqlSession.getMapper(ScoreMapper.class);
    //执行sql,返回结果对象
    List<Score> scores = mapper.selectScore();
    for (Score score : scores) {
    
    
        System.out.println(score);
    }
    sqlSession.close();
}

注意点:

  • mapper需要在xml中注册
  • 可以使用注解sql和xml配置sql相结合

Mybatis配置解析

  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息

  • configuration(配置)

    • 在xml中的配置选项要按照规定的顺序
  • properties(属性)

    • 这些属性可以在外部进行配置,并可以进行动态替换

    •   <properties resource="org/mybatis/example/config.properties">
      
    • 可以在 SqlSessionFactoryBuilder.build() 方法中传入属性值

    • 优先级:方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性

  • settings(设置)

  • typeAliases(类型别名)

    • 类型别名可为 Java 类型设置一个缩写名字,用于 XML 配置,意在降低冗余的全限定类名书写

    •   <typeAlias alias="Author" type="domain.blog.Author"/>
      
    • 可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

    • 在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名

    • 有注解,则别名为其注解值

    •   @Alias("author")
      
    • 存在常见的 Java 类型内建的类型别名(见官方文档)

  • typeHandlers(类型处理器)

  • objectFactory(对象工厂)

  • plugins(插件)

  • environments(环境配置)

  • environment(环境变量)

    • 尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境
  • transactionManager(事务管理器)

    • 有两种:JDBC|MANAGED
  • dataSource(数据源)

    • 内建:UNPOOLED|POOLED|JNDI
    • 第三方:c3p0|dhcp|
    • POOLED这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间
    • JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用
    • UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接
  • databaseIdProvider(数据库厂商标识)

  • mappers(映射器)

    •   <!-- 使用相对于 类路径 的资源引用 -->
        <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
      
    •   <!-- 使用映射器 接口实现类 的完全限定类名 -->
        <mapper class="org.mybatis.builder.AuthorMapper"/>
      
    •   <!-- 将包内的映射器 接口 实现全部注册为映射器 -->
        <package name="org.mybatis.builder"/>
      

resultMap

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

  •   <!--结果集映射-->
      <!--type为对应的实体类名,id为sql标签中resultType映射-->
      <resultMap id="userResultMap" type="User">
      	<!--column为数据库中的列名,property为实体类的属性-->
          <id property="id" column="user_id" />
          <result property="username" column="user_name"/>
          <result property="password" column="hashed_password"/>
      </resultMap>
    

日志工厂

logImpl

  • STDOUT_LOGGING

指定 MyBatis 所用日志的具体实现,未指定时将自动查找。

<!--标准的日志工厂实现-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
  • LOG4J

通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;

可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程;

需要导入依赖的jar包

  • LOG4J使用的配置文件

    # priority  :debug<info<warn<error
    #you cannot specify every priority with different file for log4j
    log4j.rootLogger=debug,stdout,info,warn,error,fileAppender
    
    ### 配置输出到文件 ###
    log4j.appender.fileAppender = org.apache.log4j.FileAppender
    log4j.appender.fileAppender.File = logs/log.log
    log4j.appender.fileAppender.Append = true
    log4j.appender.fileAppender.Threshold = DEBUG
    log4j.appender.fileAppender.layout = org.apache.log4j.PatternLayout
    log4j.appender.fileAppender.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    #%p %l
    
    #console
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%m%n
    
    #info log
    log4j.logger.info=info
    log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.info.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.info.File=./src/com/hp/log/info.log
    log4j.appender.info.Append=true
    log4j.appender.info.Threshold=INFO
    log4j.appender.info.layout=org.apache.log4j.PatternLayout
    log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #debug log
    log4j.logger.debug=debug
    log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.debug.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.debug.File=./src/com/hp/log/debug.log
    log4j.appender.debug.Append=true
    log4j.appender.debug.Threshold=DEBUG
    log4j.appender.debug.layout=org.apache.log4j.PatternLayout
    log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #warn log
    log4j.logger.warn=warn
    log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.warn.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.warn.File=./src/com/hp/log/warn.log
    log4j.appender.warn.Append=true
    log4j.appender.warn.Threshold=WARN
    log4j.appender.warn.layout=org.apache.log4j.PatternLayout
    log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #error
    log4j.logger.error=error
    log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.error.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.error.File = ./src/com/hp/log/error.log
    log4j.appender.error.Append = true
    log4j.appender.error.Threshold = ERROR
    log4j.appender.error.layout = org.apache.log4j.PatternLayout
    log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    

复杂查询

多对一查询

  • 子查询

  •   <select id="getCourse" resultMap="CourseMap">
          select * from course
      </select>
      <resultMap id="CourseMap" type="Course">
          <result column="课号" property="cid"/>
          <result column="课名" property="cName"/>
          <result column="任课教师编号" property="tid"/>
          <result column="教室" property="classroom"/>
          <result column="先修课" property="course"/>
          <association property="teacher" column="任课教师编号" javaType="Teacher" select="getTeacher"/>
      </resultMap>
      <select id="getTeacher" resultMap="TeacherMap" parameterType="String">
          select *
          from teacher
          where 工号 = #{tid}
      </select>
      <resultMap id="TeacherMap" type="Teacher">
          <result column="工号" property="tid"/>
          <result column="姓名" property="tName"/>
          <result column="性别" property="gender"/>
          <result column="生日" property="birthday"/>
          <result column="职称" property="title"/>
          <result column="婚否" property="marry"/>
          <result column="工资" property="paying"/>
      </resultMap>
    
    • association:关联
    • result:将数据库的列名对应一个实体类的变量
    • property:对应实体类中的变量,查询到的结果返回到指定的变量中
    • column:上一条查询得到的结果中的指定列,用于下一条查询的参数(类似于子查询)
    • javaType:java实体类的类型 ,指定返回的实体类型
    • select:下一条要执行的查询
  • 联表查询

  •   <select id="getCourse2" resultMap="CourseMap2">
          select  c.课号,c.课名,t.姓名
          from course  c join teacher t
          on c.任课教师编号 = t.工号
      </select>
      <resultMap id="CourseMap2" type="Course">
          <result property="cid" column="课号"/>
          <result property="cName" column="课名" />
          <association property="teacher" javaType="Teacher">
              <result property="tName" column="姓名"/>
          </association>
      </resultMap>
    
    • 将查询到的结果返回到指定的变量中

一对多查询

  • 按结果映射

    <resultMap id="TeacherMap" type="Teacher">
        <result column="工号" property="tid"/>
        <result column="姓名" property="tName"/>
        <result column="性别" property="gender"/>
        <result column="生日" property="birthday"/>
        <result column="职称" property="title"/>
        <result column="婚否" property="marry"/>
        <result column="工资" property="paying"/>
        <collection property="courses" javaType="ArrayList" ofType="Course">
            <result column="课号" property="cid"/>
            <result column="课名" property="cName"/>
            <result column="任课教师编号" property="tid"/>
            <result column="教室" property="classroom"/>
            <result column="先修课" property="course"/>
        </collection>
    </resultMap>
    <select id="getTeacher" resultMap="TeacherMap">
        select c.*,t.工号,t.姓名
        from teacher t join course c
        on t.工号 = c.任课教师编号
        where t.工号 = #{tid}
    </select>
    
    • ofType:查询返回的结果对象的类型
  • 按查询嵌套处理

    <select id="getTeacher2" resultMap="TeacherMap2">
        select * from teacher where 工号 = #{tid}
    </select>
    <resultMap id="TeacherMap2" type="Teacher">
        <result column="工号" property="tid"/>
        <result column="姓名" property="tName"/>
        <result column="性别" property="gender"/>
        <result column="生日" property="birthday"/>
        <result column="职称" property="title"/>
        <result column="婚否" property="marry"/>
        <result column="工资" property="paying"/>
        <collection property="courses" javaType="ArrayList" ofType="Course" column="工号" select="getCourses"/>
    </resultMap>
    <select id="getCourses" resultMap="CourseMap">
        select * from course where 任课教师编号 = #{tid}
    </select>
    <resultMap id="CourseMap" type="Course">
        <result column="课号" property="cid"/>
        <result column="课名" property="cName"/>
        <result column="任课教师编号" property="tid"/>
        <result column="教室" property="classroom"/>
        <result column="先修课" property="course"/>
    </resultMap>
    

动态SQL

IF

  • 可以传入多个参数,选择多个条件

  • where 1=1 不安全

<select id="getCourseByIF" resultMap="CourseMap">
    select *
    from course
    <where>
        <if test="tid != null">
            and 任课教师编号 = #{tid}
        </if>
        <if test="cName != null">
            and 课名 = #{cName}
        </if>
    </where>
</select>

choose(when,otherwise)

  • 只允许传入一个参数,选择一个条件
  • 前面语句成立时优先
  • 类似于switch
<select id="getCourseByWhen" resultMap="CourseMap">
    select *
    from course
    <where>
        <choose>
            <when test="tid != null">
                and 任课教师编号 = #{tid}
            </when>
            <when test="cName != null">
                and 课名 = #{cName}
            </when>
            <otherwise>
                and 课名 = #{cName}
            </otherwise>
        </choose>
    </where>
</select>

trim(where,set)

  • 可以通过自定义 trim 元素来定制 where 元素或set元素的功能。

  • 会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

  •   <!--prefix前缀-->
      <trim prefix="WHERE" prefixOverrides="AND |OR ">
        ...
      </trim>
      <!--suffix后缀-->
      <trim prefix="SET" suffixOverrides=",">
        ...
      </trim>
    
  • set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号

  •   <update id="upDateByTrim" parameterType="map">
          update course
          <set>
              <if test="cName != null">
                  课名 = #{cName},
              </if>
              <if test="tid != null">
                  任课教师编号 = #{tid},
              </if>
              <if test="classroom != null">
                  教室 = #{classroom},
              </if>
              <if test="course != null">
                  先修课 = #{course},
              </if>
          </set>
          where 课号 = #{cid}
      </update>
    

Foreach

  • 它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符
<select id="getCourseByForeach" resultMap="CourseMap" parameterType="map">
    select *
    from course
    <where> 
        <foreach collection="cids" item="cid" open="课号 in (" close=")" separator=",">
            #{cid}
        </foreach>
    </where>
</select>

SQL片段

  • 原理:对sql语句进行封装
  • 提高代码的重用,提高效率
  • where语句不加入sql片段
<!--定义sql片段-->
<sql id="if-tid-cName">
    sql语句···
</sql>
<!--调用sql片段-->
<include refid="if-tid-cName"></include>

缓存

什么是缓存

  • 存在内存中的数据
  • 将一次查询数据放在缓存中,之后再查询相同的数据,直接在缓存中取,不在连接数据库去查询,减少了与数据库的交互,提到效率,解决了高并发系统的性能问题

一级缓存

  • 默认情况下,只启用了本地的会话缓存
  • 仅仅对一个会话中的数据进行缓存
  • 同一个sqlSession对象的缓存

在这里插入图片描述

  • 缓存失效的原因:

    • 不是同一个sqlSession对象
    • 数据被修改
    • 手动清理缓存
    sqlSession.clearCache(); //清理缓存
    

二级缓存

  • 启用全局的二级缓存,只需要在你的 SQL 映射文件中添加 一行

  • 可以自定义参数配置二级缓存

  • 缓存只作用于 cache 标签所在的映射文件中的语句。

  • 二级缓存是基于namespace级别的缓存

  • 在xml配置文件中,开启全局缓存,默认为true

<setting name="cacheEnabled" value="true"/>
  • 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新,即当sqlSession关闭后,二级缓存取得一级缓存的数据

在这里插入图片描述

数据查询过程

  • 查看二级缓存
  • 查看一级缓存
  • 查找数据库

猜你喜欢

转载自blog.csdn.net/qq_46631261/article/details/121571409