花了一个星期入门的Mybatis到底长啥样


  • 花了一个星期的时间,算是初步入门了Mybatis这个Dao层框架

  • 简而言之,Mybatis简化了传统JDBC的操作。MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射

  • Mybatis环境搭建:JDK1.8 MySQL 5.7.19 maven-3.6.1 IDEA2019.2

    第一个Mybatis程序

    • 创建数据库(自己用SQLyog创建)

    • 导入Mybatis相关包(还有测试包junit以及后面偷懒用的lombok)

      <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.5.2</version>
      </dependency>
      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>5.1.47</version>
      </dependency>
      
    • 编写Mybatis核心配置文件

      <?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核心配置文件-->
      <configuration>
          <environments default="development">
              <environment id="development">
                  <transactionManager type="JDBC"/>
                  <dataSource type="POOLED">
                      <!--驱动-->
                      <property name="driver" value="com.mysql.jdbc.Driver"/>
                      <!--useSSL配置为false-->
                      <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="12345"/>
                  </dataSource>
              </environment>
          </environments>
          <!--每一个Mapper.xml都需要在核心配置文件中注册-->
          <!--这里resource中的路径只能用斜杠分隔-->
          <mappers>
              <mapper resource="com/shihongli/dao/UserMapper.xml"/>
          </mappers>
      </configuration>
      
    • 编写MybatisUtils工具类

      import org.apache.ibatis.io.Resources;
      import org.apache.ibatis.session.SqlSession;
      import org.apache.ibatis.session.SqlSessionFactory;
      import org.apache.ibatis.session.SqlSessionFactoryBuilder;
      
      import java.io.IOException;
      import java.io.InputStream;
      
      //工具类
      //获取sqlSessionFactory对象
      //sqlSessionFactory是用于构建sqlSession的
      public class MybatisUtils {
      
          private static SqlSessionFactory sqlSessionFactory;
      
          static {
              try {
                  //官方文档 使用Mybatis第一步
                  //获取sqlSessionFactory对象
                  String resource = "mybatis-config.xml";
                  InputStream inputStream = Resources.getResourceAsStream(resource);
                  sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
          //sqlSession包括了面向数据库执行sql命令的所有方法
          //获取SqlSession连接
          public static SqlSession getSession(){
              return sqlSessionFactory.openSession();
          }
      }
      
      
    • 编写实体类(对照数据库 有几个表就创建几个实体类 放在pojo包下)

    • 之后编写与实体类对应的Mapper接口类(之前都叫dao接口)

    • 对应Mapper接口,编写对应的Mapper.xml文件

      • 注意namespace,它是绑定Mapper接口的标志

      • namespace的命名必须跟某个接口同名

      • 接口中的方法与映射文件中sql语句id应该一一对应

      • namespace和子元素的id联合保证唯一 , 区别不同的mapper

      • namespace命名规则 : 包名+类名

        <?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.shihongli.dao.UserMapper">
        
    • 编写测试类

        @Test
          public void test() {
              //获取sqlSession对象
              SqlSession sqlSession = MybatisUtils.getSession();
              //执行sql
               //获得接口的对象,用于调用方法
              UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
              List<User> userList = userMapper.getUserList();
      
              for (User user : userList) {
                  System.out.println(user);
              }
      
              //关闭sqlSession
              sqlSession.close();
          }
      

      最好在创建module时把下面代码放到pom.xml中 防止maven读取资源出问题

      <build>
              <resources>
                  <resource>
                      <directory>src/main/java</directory>
                      <includes>
                          <include>**/*.properties</include>
                          <include>**/*.xml</include>
                      </includes>
                      <filtering>false</filtering>
                  </resource>
                  <resource>
                      <directory>src/main/resources</directory>
                      <includes>
                          <include>**/*.properties</include>
                          <include>**/*.xml</include>
                      </includes>
                      <filtering>false</filtering>
                  </resource>
              </resources>
          </build>
      

  • 注意:Mapper.xml配置文件中namespace中的名称为对应Mapper接口或者Dao接口的完整包名,必须一致

  • CRUD步骤:(使用xml开发)

    1. 在Mapper接口中定义需求接口
    2. 在Mapper.xml中添加CRUD标签
    3. 在测试类中进行测试
  • 常见标签

  • 传入的参数一律都用#{}括起来

    • select标签(查找)

      <select id="getUserById" parameterType="Integer" resultType="com.shihongli.pojo.User">
          select * from user where id = #{id}
      </select>
      
      • resultTypeSQL语句返回值类型。【完整的类名或者别名】
      • resultMap:如果实体类属性名与数据库字段名不一致时或出现一对多,多对一,多对多的情况时,使用。
      • parameterType 传入SQL语句的参数类型 。【万能的Map】
      • id:命名空间中唯一的标识符
    • 模糊查询:直接在Java代码中加通配符

      string wildcardname = “%smi%”;
      list<name> names = mapper.selectlike(wildcardname);
      
      <select id=”selectlike”>
      select * from foo where bar like #{value}
      </select>
      
    • 接口传入参数为map时

      User selectUserByNP2(Map<String,Object> map);
          
      <select id="selectUserByNP2" parameterType="map" resultType="com.kuang.pojo.User">sql略
      
      Map<String, Object> map = new HashMap<String, Object>();
      map.put("username","小明");
      map.put("pwd","123456");
      User user = mapper.selectUserByNP2(map);
      

      如果参数过多,可以考虑直接使用Map实现,如果参数比较少,直接传递参数

    • insert标签(增加)

      • insert没有resultType

      • 增删改必须要提交事务,否则不提交到数据库

        sqlSession.commit();

        或者 在Mybatis工具类openSession加入参数true,自动提交事务

    • update标签(更新)

    • delete标签(删除)

    • 所有的增删改操作都需要提交事务!

    • 接口所有的普通参数,尽量都写上@Param参数,尤其是多个参数时,必须写上!

    • 有时候根据业务的需求,可以考虑使用map传递参数!

    • 为了规范操作,在SQL的配置文件中,尽量将Parameter参数和resultType都写上!


  • 配置解析

    • mybatis-config.xml 系统核心配置文件(设置mybatis行为设置和属性信息)

    • 配置内容

      configuration(配置)
      properties(属性)
      settings(设置)
      typeAliases(类型别名)
      typeHandlers(类型处理器)
      objectFactory(对象工厂)
      plugins(插件)
      environments(环境配置)
      environment(环境变量)
      transactionManager(事务管理器)
      dataSource(数据源)
      databaseIdProvider(数据库厂商标识)
      mappers(映射器)
      <!-- 注意元素节点的顺序!顺序不对会报错 -->
      

      常用 configuration properties settings typeAliases environments mappers

    • environments元素

      • <environments default="development">
                <environment id="development">
                    <transactionManager type="JDBC"/>
                    <dataSource type="POOLED">
                        <!--驱动-->
                        <property name="driver" value="${driver}"/>
                        <!--useSSL配置为false,amp的作用是转义-->
                        <property name="url" value="${url}"/>
                        <property name="username" value="${username}"/>
                        <property name="password" value="${password}"/>
                    </dataSource>
                </environment>
            </environments>
        
    • Mappers元素

      • mapper作为映射器,用于定义映射SQL语句文件
      • 映射就是 告诉Mybatis去哪找这些语句

      引入资源的方式:(三种都需要掌握)

      <!--每一个Mapper.xml都需要在核心配置文件中注册-->
      <!--这里resource中的路径只能用斜杠分隔-->
      
      <!-- 使用相对于类路径的资源引用 resource只能用/分隔 这种引用方式不要求在同一个包下 只要找得到即可 -->
      <mappers>
       <mapper resource="org/mybatis/builder/PostMapper.xml"/>
      </mappers>
      
      <!--
      使用映射器接口实现类的完全限定类名
      需要配置文件名称和接口名称一致,并且位于同一目录下
      -->
      <mappers>
        <mapper class="org.mybatis.builder.AuthorMapper"/>
      </mappers>
      
      <!--
      将包内的映射器接口实现全部注册为映射器
      但是需要配置文件名称和接口名称一致,并且位于同一目录下
      -->
      <mappers>
        <package name="org.mybatis.builder"/>
      </mappers>
      
    • Properties元素(在JDBC中也使用过)

      • 1 在资源目录下新建db.properties(这是我本地的)

        driver=com.mysql.jdbc.Driver
        url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
        username=root
        password=12345
        
      • 文件导入properties配置文件

        <configuration>
            <!--导入properties文件-->
            <properties resource="db.properties"/>
            .......
        </configuration>
        
    • typeAliases别名优化:为 Java 类型设置一个短的名字,用于减少包名+类名的冗余

      • 为单独的实体类设置别名

      • <typeAliases>
                <!--给实体类起别名-->
               <typeAlias type="com.shihongli.pojo.User" alias="User"/>
            </typeAliases>
        
      • 为整个包设置别名,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

      • <typeAliases>
                <!--给实体类起别名-->
        <!--        <typeAlias type="com.shihongli.pojo.User" alias="User"/>-->
                <package name="com.shihongli.pojo"/>
            </typeAliases>
        
      • 通过注解设置别名

      • @Alias("user")
        public class User {
            ...
        }
        
    • settings设置(常用cacheEnabled lazyLoadingEnabled mapUnderscoreToCamelCase logImpl)

      • <settings>
          <setting name="cacheEnabled" value="true"/>
          <setting name="lazyLoadingEnabled" value="true"/>
          <setting name="multipleResultSetsEnabled" value="true"/>
          <setting name="useColumnLabel" value="true"/>
          <setting name="useGeneratedKeys" value="false"/>
          <setting name="autoMappingBehavior" value="PARTIAL"/>
          <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
          <setting name="defaultExecutorType" value="SIMPLE"/>
          <setting name="defaultStatementTimeout" value="25"/>
          <setting name="defaultFetchSize" value="100"/>
          <setting name="safeRowBoundsEnabled" value="false"/>
          <setting name="mapUnderscoreToCamelCase" value="false"/>
          <setting name="localCacheScope" value="SESSION"/>
          <setting name="jdbcTypeForNull" value="OTHER"/>
          <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
        </settings>
        
    • 各个对象作用域

      • SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
      • SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
      • SqlSession 的最佳的作用域是请求或方法作用域。

    日志工厂

    • 在核心配置文件的settings中配置日志输出

    • STDOUT_LOGGING(Mybatis自带标准日志输出)

    • <settings>
              <setting name="logImpl" value="STDOUT_LOGGING"/>
      </settings>
      
    • log4j(log for Java)

      1. 导入log4j的包

      2. <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        
      3. 编写配置文件log4j.properties

      4. #将等级为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
        
      5. setting实现日志

      6. <settings>
            <setting name="logImpl" value="LOG4J"/>
        </settings>
        
      7. 测试:Logger.getLogger(MyTest.class);返回一个测试Logger类


  • 一对多&多对一(需要多练习)这里只写我熟悉的一种写法

  • 多对一

    1. 数据库设计

    2. 搭建测试环境(核心配置文件 工具类 pojo dao(Mapper Mapper.xml))

    3. lombok插件(导包)

      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
      </dependency>
      
    4. 使用resultMap并且多对一表示关联,使用association标签

      这种方法 不用分开sql语句 映射关系相对于另一种麻烦了一点

      <select id="getStudentInfo1" resultMap="StudentTeacher1">
          select s.id sid,s.name sname,t.name tname,t.id tid
          from student s, teacher t
          where s.tid = t.id;
      </select>
      
      <resultMap id="StudentTeacher1" type="Student">
          <!--        对结果进行处理-->
          <!--        这里相当于是对student中的Student类的对象进行 分别的属性处理-->
          <result property="id" column="sid"/>
          <result property="name" column="sname"/>
          <!--        对其中的复杂类型teacher单独处理-->
          <!--        这里实际上是对teacher这个对象对应的Teacher类 进行了一次嵌套,里面是Teacher类的属性-->
          <association property="teacher" javaType="Teacher">
              <!--            再次进行嵌套-->
              <result property="name" column="tname"/>
              <result property="id" column="tid"/>
          </association>
      </resultMap>
      
    5. 注意记得在核心配置文件中注入mapper/或者直接注入包(前提是名字一致且在同一包下)

    • 一对多

      • 之前配置同上

      • Mapper.xml语句

            <select id="getTeacherById" resultMap="TeacherStudent">
              select s.id sid, s.name sname , t.name tname, t.id tid
              from student s,teacher t
              where s.tid = t.id and t.id=#{id}
            </select>
            <resultMap id="TeacherStudent" type="Teacher">
        <!--        在数据库的表中别名也算column的名字-->
                <result property="id" column="tid"/>
                <result property="name" column="tname"/>
        <!--        复杂的对象需要单独处理     对象(多对一)association 集合(一对多)-->
        <!--        这里不需要写javaType的原因是 这里已经对应取的是这个集合中的各个元素的属性了-->
                <collection property="students" ofType="Student">
                    <result property="id" column="sid"/>
                    <result property="name" column="sname"/>
                    <result property="tid" column="tid"/>
                </collection>
            </resultMap>
        
    • 总结:

      1、关联-association

      2、集合-collection

      3、所以association是用于一对一和多对一,而collection是用于一对多的关系

      4、JavaType和ofType都是用来指定对象类型的

      • JavaType是用来指定pojo中属性的类型

      • ofType指定的是映射到list集合属性中pojo的类型。(可以理解为泛型)

        JavaType是用来指定pojo中属性的类型
        ofType指定的是映射到list集合属性中pojo的类型
        

    • 动态SQL:指的是根据不同的查询条件 , 生成不同的Sql语句

    • 会用几个常用的标签

      • if标签(最经常使用的 相当于JDBC中sql语句拼接)

        <if test="title != null">
                title = #{title}
        </if>
        <if test="author != null">
                and author = #{author}
        </if>
        
      • where标签

        <where>
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
        </where>
        
      • “where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。(反正写上就完事了)

      • Set标签(用于Update标签)

        <update id="updateBlog" parameterType="map">
            update blog
              <set>
                  <if test="title != null">
                      title = #{title},
                  </if>
                  <if test="author != null">
                      author = #{author}
                  </if>
              </set>
            where id = #{id};
        </update>
        
      • set标签与where标签用法基本一致,用于去除多余的逗号

      • choose(when otherwise)标签

      • 类似java中switch-case语句

        <select id="queryBlogChoose" parameterType="map" resultType="Blog">
            select * from mybatis.blog
            <where>
                <choose>
                    <when test="title != null">
                        title = #{title}
                    </when>
                    <when test="author != null">
                        and author = #{author}
                    </when>
                    <otherwise>
                        and views = #{views}
                    </otherwise>
                </choose>
            </where>
        </select>
        
      • SQL片段(sql标签)sql片段不要包括where

        • 1.提高复用性 提取sql片段

          <sql id=“xxx”
               xxx
               </sql>
          
        • 2.引用sql片段

        • <include refid="if-title-author"></include>
          
      • foreach

      • 传入一个map

      • <!--    select * from mybatis.blog where 1=1 and id in (1,2,3);-->
        <!--    foreach标签中的 collection可以根据map的key的值获取集合-->
        	   collection:指定输入对象中的集合属性key值
               item:每次遍历生成的对象
               open:开始遍历时的拼接字符串
               close:结束时拼接的字符串
               separator:遍历对象之间需要拼接的字符串
            <select id="queryBlogForeach" parameterType="map" resultType="Blog">
                select * from mybatis.blog
                <where>
                    <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                        id = #{id}
                    </foreach>
                </where>
            </select>
        

    缓存

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

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

      • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
      • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库
      • 一级缓存自动开启
    • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

      基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

      工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;

    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;

    • 新的会话查询信息,就可以从二级缓存中获取内容;

    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

      • 使用步骤

        在核心配置文件中设置开启

      • <setting name="cacheEnabled" value="true"/>
        

        在mapper.xml中配置使用二级缓存

        <cache/>
        或者
        <cache
          eviction="FIFO"
          flushInterval="60000"
          size="512"
          readOnly="true"/>
        这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
        
    • 注解开发(Mybatis中注解只能进行比较简单的sql语句,复杂的语句还是用xml开发)

    • 映射并不能用注解来构建

      • 常见注解:

        • @select ()
        • @update ()
        • @Insert ()
        • @delete ()
        • 使用注解之后只需改变两个地方:mapper和测试类,不需要在mapper.xml中写SQL语句了

        • 1.添加注解

        • //查询全部用户
          @Select("select id,name,pwd password from user")
          public List<User> getAllUser();
          
        • 2.核心配置文件注入(绑定接口)

          <!--使用class绑定接口-->
          <mappers>
              <mapper class="com.kuang.mapper.UserMapper"/>
          </mappers>
          
    • 面向接口编程:根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好

      • 其他注解实例

      • //添加一个用户
        @Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})")
        int addUser(User user);
        
      • //修改一个用户
        @Update("update user set name=#{name},pwd=#{pwd} where id = #{id}")
        int updateUser(User user);
        
      • //根据id删除用
        @Delete("delete from user where id = #{id}")
        int deleteUser(@Param("id")int id);
        

      @Param注解用于给方法参数起一个名字。以下是总结的使用原则:

      • 在方法只接受一个参数的情况下,可以不使用@Param。
      • 在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
      • 如果参数是 JavaBean(参数为引用类不用加,如果是基本数据类型和string一定要加上) , 则不能使用@Param。
      • 不使用@Param注解时,参数只能有一个,并且是Javabean。

      #{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符? 【推荐使用】

      ${} 的作用是直接进行字符串替换

使用注解和配置文件协同开发,才能最大利用Mybatis!


后续:
用了一个星期的碎片时间,把mybatis入门了,之后一段时间先看spring再看springmvc,最后ssm整合,希望能在7.10号之前完成!-2020.06.05晚22.22

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值