MyBatis持久层框架与MybatisPlus

1.概念

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

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

 2.内部组件结构图

 MyBatis持久层框架与MybatisPlus_第1张图片

 3.导入依赖

       
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.4
        

        
        
            mysql
            mysql-connector-java
            5.1.48

        

 4.核心配置文件


 
     
         
             
             
              
             
                 
                 
             

         

     

     

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 list = sqlSession.selectList("hello.get");

        for (User u : list) {

                System.out.println(u);

        }

       

6.ResultMap简单使用

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

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

例子: 

 
    
    

        

        

        

        
        
    

   

 

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容器管理 
    //配置类:将方法的返回值交给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 names = mapper.selectlike(wildcardname);

   

例子2

    string wildcardname = “smi”;
   list names = mapper.selectlike(wildcardname);

    

(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序列化接口(可用来保存对象的状态),可在它的映射文件中配置

(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对象。

你可能感兴趣的:(数据库架构)