1.概念

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。

  1. 简化JDBC的开发
  2. 能够更好的完成ORM(Object Relational Mapping对象关系映射)

 2.内部组件结构图

 

springboot实现数据库故障自动切换_数据库架构

 3.导入依赖

 

<!--mybatis依赖包-->
         <dependency>
             <groupId>org.mybatis.spring.boot</groupId>
             <artifactId>mybatis-spring-boot-starter</artifactId>
             <version>2.1.4</version>
         </dependency>
         <!--jdbc依赖包-->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.48</version>        </dependency>

 4.核心配置文件

<!-- mybatis的核心配置文件 -->
  <configuration>
      <environments default="test">
          <environment id="test">
              <transactionManager type="JDBC"></transactionManager>
              <dataSource type="POOLED">
              <property name="driver" value="com.mysql.jdbc.Driver"/> 
             <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai" /> 
                 <property name="username" value="root"/> 
                 <property name="password" value="root"/> 
              </dataSource>
          </environment>
      </environments>
      <mappers><mapper resource="mappers/UserMapper.xml"/></mappers>
 </configuration>

5.实现代码

//1,创建SqlSessionFactory对象,线程非安全,用来产生SqlSession
         //2,创建SqlSession,用来执行sql
         //3, 定位SQL: namespace的值+id的值,可以只传入id,但是,如果在mybatis的环境中有多个                                   相同id的映射名称,就会报错。
         //4,解析结果并打印
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory session = new SqlSessionFactoryBuilder().build(in);
         SqlSession sqlSession = session.openSession();
         List<User> list = sqlSession.selectList("hello.get");        for (User u : list) {
                System.out.println(u);
        }
<mapper namespace="hello">
        <select id="get" resultType="cn.tedu.pojo.User">
              select * from user
        </select>
</mapper>

6.ResultMap简单使用

当数据库的字段名和对象的属性名一致时,可以用简单属性resultType。

但是当数据库中的字段名称和对象中的属性名称不一致时,就需要resultMap属性。

例子: 

<mapper namespace="cn.tedu.mybatis.pojo.PersonMapper">
     <!-- 最强大对象resultMap,结果封装到哪个pojo对象,type就是谁 -->
     <resultMap type="Person" id="personRM">        <!-- 映射主键 -->
        <id column="id" property="id"/>
        <!-- 映射其他列 -->
        <!—单独处理属性名和字段名不一致的 -->
         <result property="userName" column="user_name"/>
     </resultMap>

     <select id="find"  resultMap="personRM">
         SELECT id,user_name FROM person WHERE id=#{id}
     </select> <mapper>

7.#{}与${}区别

#{}是预编译处理,${}是字符串替换。

Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;

Mybatis 在处理${}时,就是把${}替换成变量的值。

总结:

          使用#{}进行预编译处理,可以有效的防止 SQL 注入攻击,提高系统安全性。

注意:order by后面的关键字必须用${}

           传递表名时必须用${}

            其他情况能使用#{}就不要使用${}

8.MyBatis与SpringBoot进行整合

(1)xml文件

#spring整合数据源 最快的数据源
 spring:
   datasource:
     #使用高版本驱动时使用cj
     #serverTimezone=GMT%2B8   东8区   %2B +号
     #&useUnicode=true&characterEncoding=utf8 是否开启unicode编码/utf-8
     #&autoReconnect=true  断线是否重连
     #&allowMultiQueries=true 是否允许批量操作
     driver-class-name: com.mysql.cj.jdbc.Driver
     url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
     username: root
     #如果密码以数字0开头,则使用""号包裹  "0123456"
     password: root#SpringBoot整合Mybatis配置
 mybatis:
   #设置别名包
   type-aliases-package: com.jt.pojo
   #加载映射文件
   mapper-locations: classpath:/mappers/*.xml
   #开启驼峰映射
   configuration:
     map-underscore-to-camel-case: true

(2)为接口创建代理对象

@Mapper

@MapperScan("com.jt.mapper")

(3)实现数据查询时有2种Sql的写法

    将所有的Sql语句都写到xml 映射文件中. (万能操作方式)

    可以将Sql语句通过注解的方式标识在接口方法中.(只适用于简单操作)

       @select  @insert  @update  @delete

9.MyBatisPlus

使用MP主要完成单表的CURD操作简化开发

(1) 说明:

  1. POJO应该与数据库中的表完成映射
  2. POJO中的属性与表中的字段一一映射

     注解:

  1. @TableName(“demo_user”) //实现对象与表名映射
  2. //设定主键自增 @TableId(type = IdType.AUTO)
  3. @TableField(“name”) 实现属性与字段映射(如果属性与字段的名称一致,则注解可以省略)

(2)Mapper继承公共的接口BaseMapper,添加泛型对象

(3)创建条件构造器,封装where条件(默认的关系链接符 and)

            逻辑运算符 > gt, < lt, = eq, >= ge, <= le, != ne

            like:leftlike,rightlike

            关键字: order by 排序     默认规则: 升序 asc 降序 desc

     QueryWrapper queryWrapper = new QueryWrapper();

(4)利用MP实现分页查询查询

PageResult
 
 
@Data
@Accessors(chain = true)
public class PageResult {
    private String query; //查询的key
    private Integer pageNum; //页数
    private Integer pageSize; //条数
    private Long total; //总数
    private Object rows; //分页后的结果
}  
UserController

/**
 * 需求: 利用分页展现用户user列表数据
 * URL: /user/list   GET方式
 * 请求参数:  http://localhost:8091/user/list?query=查询关键字&pageNum=1&pageSize=10
 * 返回值: SysResult对象(PageResult)
 * */
@GetMapping("/list")
public SysResult getUserList(PageResult pageResult){
    pageResult = userService.getUserList(pageResult);
    return SysResult.success(pageResult);
} 
UserServiceImpl
 
 
/**
 * 利用MP的方式实现分页查询
 * API说明:selectPage(arg1,arg2)
 * arg1:  MP中的分页对象  固定的
 * arg2:  MP分页中的条件构造器
 * @param pageResult
 * @return
 */
@Override
public PageResult getUserList(PageResult pageResult) {
    //1.定义MP的分页对象  arg1:页数  arg2:行数
    IPage iPage = new Page(pageResult.getPageNum(),pageResult.getPageSize());
    //2.构建查询条件构造器
    QueryWrapper queryWrapper = new QueryWrapper();
    //判断用户数据是否有效   有效true  无效false
    boolean flag = StringUtils.hasLength(pageResult.getQuery());
    queryWrapper.eq(flag,"username",pageResult.getQuery());
    //经过MP分页查询将所有的分页数据(total/结果/页面/条数)封装到iPage对象
    iPage = userMapper.selectPage(iPage,queryWrapper);
    //从分页对象中获取分页@Transactional后的总记录数/结果
    return pageResult.setTotal(iPage.getTotal()).setRows(iPage.getRecords());
}
MP配置类
 
 
//命名规则:类似于配置文件 则把这个类称之为"配置类" 一般Config接我
@Configuration //标识是一个配置类(代替之前的xml文件)
public class MybatisPlusConfig {
    //铺垫:xml中通过标签管理对象,将对象交给Spring容器管理 <Bean>
    //配置类:将方法的返回值交给Spring容器管理 @Bean注解

    /**
     * 关于MP分页规则说明
     *  规则:需要设定一个拦截器,将分页的sql进行动态的拼接
     *  sql规则:现在的sql都支持sql92标准
     * */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new                      PaginationInnerInterceptor(DbType.MARIADB));
        return interceptor;
    }
}

(5)MP实现自动填充

//pojo基类,完成2个任务,2个日期,实现序列化
@Data
@Accessors(chain=true)
public class BasePojo implements Serializable{
   @TableField(fill = FieldFill.INSERT)
   private Date created;  //表示入库时需要赋值
   @TableField(fill = FieldFill.INSERT_UPDATE)
   private Date updated;  //表示入库/更新时赋值.
}
MP对外暴露了一个自动填充的接口MetaObjectHandler ,用户只需要实现该接口,并且重写其中的方法。即可以实现自动填充的功能。
@Component //将对象交给Spring容器管理  不属于C/S/M
public class MyMetaObjectHandler implements MetaObjectHandler {

    // 入库操作时调用created/updated
    /**
     * setFieldValByName(arg1,arg2,arg3)
     * arg1 自动填充的字段名称
     * arg2 自动填充的值
     * arg3 metaObject(固定写法)
     */

    @Override
    public void insertFill(MetaObject metaObject) {
        //设定时间变量
        Date date = new Date();
        this.setFieldValByName("created", date, metaObject);
        this.setFieldValByName("updated", date, metaObject);
    }

    //更新操作时调用updated
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updated", new Date(), metaObject);
    }
}

10.面试题:

(1)当实体类中的属性名和表中的字段名不一样 ,怎么办?

  1. 在Mapper.xml文件中使用resultMap来定义映射规则
  2. 写SQL语句时起别名

(2)模糊查询like怎么写?

  1. 在java代码中添加SQL通配符%(传参)    
  2. 在SQL语句拼接通配符%,但是可能会引起SQL注入攻击
例子1: 
   string wildcardname = “%smi%”;
    list<name> names = mapper.selectlike(wildcardname);   <select id=”selectlike”>
       select * from foo where bar like #{value}
    </select>例子2
    string wildcardname = “smi”;
    list<name> names = mapper.selectlike(wildcardname);    <select id=”selectlike”>
        select * from foo where bar like "%"#{value}"%"
     </select>

(3)Mybatis Dao层 接口的工作原理是什么?

       Dao接口的工作原理是JDK动态代理,Mybatis运行时,使用JDK动态代理为Dao接口生成代理对象。

(4)Mybatis 的一级、二级缓存?

一级缓存:

       Mybatis支持缓存,但在没有配置的情况下,默认情况下它只启用一级缓存。级别1缓存只对相同的SqlSession启用。因此,如果SQL参数一模一样,我们使用相同的SqlSession对象调用映射方法,通常只执行SQL一次,因为第一个查询使用SelSession MyBatis将把它放在缓存中,和将来查询,如果没有声明需要刷新,如果缓存中没有,SqlSession将获取当前缓存的数据,并且不会再次向数据库发送SQL。

二级缓存:

       MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。二级缓存与一级缓存其机制相同,默认也是采用PerpetualCache,HashMap存储,不同在于其存储作用域为Mapper(Namespace),并且可自定义存储源,如Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置<cache/>。

(5)什么是 MyBatis 的接口绑定?有哪些实现方式?

       接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。

       接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上@Select、@Update等注解,里面包含Sql语句来绑定;另外一种就是通过xml里面写SQL来绑定,在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。

总结:当Sql语句比较简单时候,用注解绑定,当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。

(6)使用 MyBatis 的 mapper 接口调用时有哪些要求?

  1. Mapper接口方法名和mapper.xml中定义的每个sql的id相同; 
  2. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同;
  3. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;
  4. Mapper.xml文件中的namespace即是mapper接口的类路径。
     

 (7)JDBC和MyBatis的区别?

       JDBC是java提供了一套专门用于和数据库对接的api,java.sql.*,其规范了如何和数据库进行对接,实现由各数据库厂商进行各自的实现和扩展。学习JDBC重点在学习如何使用其api。

       MyBatis框架是轻量级封装了JDBC,我们已经看不到这些api,连接connection、语句preparedstatement、结果集ResultSet,而关注的是mybatis框架体系如何去使用,一旦写好,我们关注的是java对象。