MyBatis-04-实用技巧

Posted primabrucexu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis-04-实用技巧相关的知识,希望对你有一定的参考价值。

五、ResultMap——结果集映射

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

5.1 查询为null的问题

  • 什么时候会出现这个问题?

    • 实体类中设置的属性名和数据库中的字段名不一致
  • 问题复现

    • 数据库中字段设置

      技术图片

    • 实体类中的属性设置

      public class User {
          private int id;
          private String name;
          private String password;
      }
      
    • 查询测试

      @Test
      public void test() {
          SqlSession sqlSession = MyBatisUtils.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          List<User> list = mapper.getUsers();
          for (User user : list) {
              System.out.println(user);
          }
          sqlSession.close();
      }
      

      技术图片

    • 从查询结果中可以看出,数据库中的pwd字段没有正确映射到实体类中的password属性上

5.2 问题分析

  • 对SQL语句的分析:

    select * from user <==> select id,name,pwd from user
    
  • MyBatis通过查询语句中的字段,去对应的实体类中查找相应属性名的set方法。但是,在本例中,实体类中没有pwd的set方法,所以字段pwd的值无法赋值给实体类,也就造成了查询结果中放回为null的情况

  • 解决方法

    • 指定别名,使得别名和java类中的属性名一一对应

    • 使用结果集进行映射

      <resultMap id="UserMap" type="User">
          <!-- column是数据库表的列名, property是对应实体类的属性名-->
      	<id column="id" property="id"/>
      	<result column="name" property="name"/>
      	<result column="pwd" property="password"/>
      </resultMap>
      

5.3 ResultMap

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

1. 自动映射

  • 对于简单的语句,我们可以不用手动配置ResultMap,因为ResultMap的自动映射完全可以满足我们的需求,我们需要做的就是确保属性名和查询到的字段名能一一对应上即可

  • 示例

    • 数据库的字段名

    技术图片

    • 实体类

      public class User {
          private int id;
          private String name;
          private String pwd;
          public User() {
          }
      }
      
    • mapper.xml

      <select id="getUsers" resultType="com.pbx.pojo.User">
          select * from user
      </select>
      
    • 测试

      @Test
      public void test() {
          SqlSession sqlSession = MyBatisUtils.getSqlSession();
          UserMapper mapper = sqlSession.getMapper(UserMapper.class);
          List<User> list = mapper.getUsers();
          for (User user : list) {
              System.out.println(user);
          }
          sqlSession.close();
      }
      

      技术图片

    • 如果说实体类中的属性和数据库的字段不同,可以在SQL设置别名进行匹配

  • 简单来说,如果你的SQL语句足够简单,那么完全不需要手动配置ResultMap,可以通过SQL设置别名来使得自动装配可以正确执行。

2. 简单的手动映射

  • 示例

    • mapper.xml
    <resultMap id="userResultMap" type="User">
      <id property="id" column="user_id" />
      <result property="username" column="user_name"/>
      <result property="password" column="hashed_password"/>
    </resultMap>
    
    <select id="selectUsers" resultMap="userResultMap">
      select user_id, user_name, hashed_password
      from some_table
      where id = #{id}
    </select>
    
  • 注意点

    • 在引用它的语句中设置 resultMap 属性就行了(注意去掉了 resultType 属性)

六、日志与分页

6.1 日志功能

  • MyBatis支持日志记录功能,需要在mybatis-config.xml文件中配置相应的参数以开启日志功能

  • mybatis-config.xml配置

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    
  • MyBatis支持的日志类型

    SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

  • 日志输出示例

    技术图片

    • 除了用户的输出之外,其余内容均是日志内容

6.2 log4j日志

  • 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等
  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

使用步骤

  1. 在maven中导入log4j的依赖

    <dependencies>
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
    
  2. 在mybatis-config.xml中开启日志记录功能

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
  3. 编写log4j.properties配置文件

    ### set log levels ###
    log4j.rootLogger = debug ,  stdout ,  D ,  E
    
    ### 输出到控制台 ###
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.encoding = UTF-8
    log4j.appender.stdout.Target = System.out
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### 输出到日志文件 ###
    log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.D.encoding = UTF-8
    log4j.appender.D.File = logs/log.log
    log4j.appender.D.Append = true
    log4j.appender.D.Threshold = DEBUG
    log4j.appender.D.layout = org.apache.log4j.PatternLayout
    log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    ### 保存异常信息到单独文件 ###
    log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.E.encoding = UTF-8
    log4j.appender.E.File = logs/error.log
    log4j.appender.E.Append = true
    log4j.appender.E.Threshold = ERROR
    log4j.appender.E.layout = org.apache.log4j.PatternLayout
    log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    

6.3 分页

1. 使用LIMIT进行分页

  • ·在SQL层面上进行分页操作

2. 使用RowBounds进行分页

  • 目前已经不流行了,这是通过Java代码实现的

  • mapper接口

    List<User> getUserByRowBounds();
    
  • mapper.xml文件

    <select id="getUserByRowBounds" resultType="user">
    	select * from user
    </select>
    
  • 测试类

    @Test
    public void testUserByRowBounds() {
    	SqlSession session = MybatisUtils.getSession();
    	int currentPage = 2; //第几页
    	int pageSize = 2; //每页显示几个
    	RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);
    	//通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]
    	List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds",null, rowBounds);
    	for (User user: users){
    		System.out.println(user);
    	}
    }
    

3. 使用插件PageHelper


七、使用注解开发

7.1 面向接口编程

  • 目的:解耦,可拓展,提高代码复用

    • 在分层开发中,上层不用管下层的具体实现,大家都会遵守共同的标准,简化开发
  • 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;

  • 各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

  • 什么是接口

    • 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
    • 接口的本身反映了系统设计人员对系统的抽象理解。
    • 接口应有两类:
      • 第一类是对一个 个体的抽象,它可对应为一个抽象体(abstract class)
      • 第二类是对一个 个体某一方面的抽象,即形成一个抽象面(interface)

7.2 MyBatis中的注解开发

  • 对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。比如,上面的 XML 示例可以被替换成如下的配置:

    public interface BlogMapper {
      @Select("SELECT * FROM blog WHERE id = #{id}")
      Blog selectBlog(int id);
    }
    
  • 对于简单的语句,使用注解可以加快开发速度。但对于一些复杂的SQL语句,注解就显得力不从心

  • MyBatis的详细执行流程

    技术图片

7.3 CRUD操作

  1. mapper接口文件

    package com.pbx.mapper;
    
    import com.pbx.pojo.User;
    import org.apache.ibatis.annotations.*;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author BruceXu
     * @since 2020/10/30
     */
    public interface UserMapper {
        @Select("select * from user")
        List<User> getUsers();
    
        @Select("select * from user where id = #{pid}")
        User getUserByID(@Param("pid") int id);
    
        @Insert("insert into user (id,name,pwd) values (#{id}, #{name}, #{pwd})")
        int insert(User user);
    
        @Update("update user set name = #{newName} where id = #{id}")
        int update(@Param("newName") String name, @Param("id") int id);
    
        @Delete("delete from user where id = #{id}")
        int delete(@Param("id") int id);
    
    }
    
  2. 注册mapper文件

    <mappers>
        <mapper class="com.pbx.mapper.UserMapper"/>
    </mappers>
    
  3. 测试类

    package com.pbx;
    
    import com.pbx.mapper.UserMapper;
    import com.pbx.pojo.User;
    import com.pbx.utils.MyBatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.List;
    
    /**
     * @author BruceXu
     * @date 2020/11/3
     */
    public class test {
        @Test
        public void test() {
            SqlSession session = MyBatisUtils.getSqlSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            List<User> list = mapper.getUsers();
            for (User user : list) {
                System.out.println(user);
            }
            System.out.println("=============================");
            mapper.insert(new User(5, "bf", "123"));
            User t = mapper.getUserByID(5);
            System.out.println(t);
            System.out.println("=============================");
            mapper.update("gf", 5);
            t = mapper.getUserByID(5);
            System.out.println(t);
            System.out.println("=============================");
            mapper.delete(5);
            list = mapper.getUsers();
            for (User user : list) {
                System.out.println(user);
            }
            System.out.println("=============================");
            session.commit();
            session.close();
        }
    }
    

    技术图片

7.4 @Param注解

  • @Param用于指定接口中参数在SQL映射的名字
    • 只有一个参数时,可以不使用(建议还是用上,养成习惯)
    • 在方法有多个参数时,基本类型+String需要使用@Param进行标注名称

以上是关于MyBatis-04-实用技巧的主要内容,如果未能解决你的问题,请参考以下文章

Android 实用代码片段

asp.net页面实用代码片段

Android课程---Android Studio使用小技巧:提取方法代码片段

超实用的php代码片段

实用代码片段

分享几个实用的代码片段(附代码例子)