栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis[狂]

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis[狂]

Mybatis[狂] 学习地址:https://www.bilibili.com/video/BV1NE411Q7Nx 备份用,学习从 07/12/2021-07/16/2021

环境:

  • JDK1.8
  • MySQL 5.7
  • maven 3.6.1
  • IDEA

回顾:

  • JDBC
  • MySQL
  • Java基础
  • Maven
  • Junit

框架:配置文件。学习最好的方式:看官网文档

1.简介 1.1 什么是mybatis
  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

如何获得mybatis

  • github
  • maven仓库

    org.mybatis
    mybatis
    3.5.2

1.2 持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据持久化方法:数据库(jdbc),io文件持久化
  • 生活中:冷藏可以让物体持久,罐头

为什么需要数据持久化?

  • 有些对象不能丢掉:存在银行的钱不能没
  • 内存成本高
1.3 持久层

Dao层,service层,controller层

  • 完成持久化工作代码的代码块
  • 层界限十分明显
1.4 为什么需要mybatis
  • 帮助程序员将数据存入数据库
  • 方便
  • 传统的jdbc代码太复杂了,简化语句利用框架
  • 不用mybatis也可以。更容易上手。技术没有高低之分
  • 优点

最重要的一点:使用的人多

spring springmvc springboot

2. 第一个Mybatis程序

思路

  • 搭建环境
  • 导入mybatis
  • 编写代码
  • 测试
2.1 搭建环境

数据库

CREATE DATAbase `mybatis`;
USE `mybatis`;

CREATE TABLE `user`(
`id` INT not null primary key,
`name` varchar(30) DEFAULT null,
`pwd` varchar(30) default null
)engine = innodb default charset=utf8;

insert into `user`(`id`,`name`,`pwd`)values
(1,'kuangshen1','123456'),
(2,'kuangshen2','123456'),
(3,'kuangshen3','123456')

新建项目

  1. 新建一个普通maven项目
  2. 删除src目录
2.2 创建一个模块
  • 编写mybatis核心配置文件




    
        
            
            
                
                
                
                
            
        
    


  • 编写工具类
package com.xu.util;

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-sqlsession
public class MybatisUtils {

    private static  SqlSessionFactory sqlSessionFactory;

    static {
        InputStream inputStream = null;
        try {
                String resource = "mybatis-config.xml";
                inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        }

        //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例
       //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();

    }
    }
2.3 编写代码
  • 实体类
  • 接口
public interface UserDao {
    List getUserList();
}
  • 接口实现类由原来的impl转换为mapper配置文件




    
        select * from mybatis.user
    

2.4 测试

注意点:

org.apache.ibatis.binding.BindingException: Type interface com.xu.dao.UserDao is not known to the MapperRegistry.

MapperRegistry是什么

核心配置文件中注册mappers

可能遇到的问题:

  1. 配置文件没有注册
  2. 绑定接口错误
  3. 方法名不对
  4. 返回类型不对
  5. Maven导出资源问题,加入以下代码:
    
        
            
                src/main/resources
                
                    ***.xml
                
                true
            

            
                src/main/java
                
                    ***.xml
                
                true
            
        
    

测试时出现的问题:

在实体类中没有重写tostring方法,导致测试时只输出结果的内存地址,重写tostring方法后解决问题

测试代码

package com.xu.dao;

import com.xu.pojo.User;
import com.xu.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {
    @Test
    public void test(){
        //获得sqlsession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        // /执行sql
        UserDao userdao = sqlSession.getMapper(UserDao.class);
        List userList = userdao.getUserList();

        //方式二
//        List userList1 = sqlSession.selectList("com.xu.dao.UserDao.getUserList");

        for (User user : userList) {
            System.out.println(user.toString());
        }
        sqlSession.close();
    }
}

测试结果

步骤:

0.导入依赖

1.MybatisUtils

2.mybatis-config.xml

3.pojo实体类

4.接口

5.dao-Mapper.xml

6.maven

7.junit测试

3. CRUD 1. namespace

namespace中的包名要和dao/mapper中名要一致

2. select

选择,查询语句

  • id:对应namespace中的方法名
  • resultType:sql执行语句的返回值
  • parameterType

步骤

  • 编写接口
//根据id查询用户
    User getUserById(int id);
  • 编写mapping中的sql语句

        select id,name,pwd as password from mybatis.user where id = #{id}

2. resultmap

结果集映射

id name pwd
⬇   ⬇    ⬇
id name password


        
        
        
    

    
        select * from mybatis.user

  1. 测试
public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //rowbounds实现
        RowBounds rowBounds = new RowBounds(1,2);

        //通过java代码层面分页
        List userList = sqlSession.selectList("com.xu.dao.UserMapper.getUserByRowBounds",null,rowBounds);
        for (User user : userList) {
            System.out.println(user);
        }

        sqlSession.close();
    }
8.3 分页插件

了解即可

9. 使用注解开发 9.1 面向接口编程

真正的开发中,都是面向接口编程

根本原因:解耦

9.2 使用注解开发
  1. 注解在接口上实现
@Select("select * from user")
    List getUsers();
  1. 需要在核心配置文件中绑定接口

        

  1. 测试

本质:反射机制实现

底层:动态代理

Mybatis详细执行流程

如何探究/学习方法:debug看一步一步的流程


9.3 CRUD(注解完成)

我们可以在工具中自动提交事务

public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
}

编写接口,增加注解

public interface UserMapper {

    @Select("select * from user")
    List getUsers();

    //方法存在多个参数,所在参数必须加上@param注解
    @Select("select * from user where id=#{id}")
    User getUserByID(@Param("id") int id);

    @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
    int addUser(User user);

    @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
    int updateUser(User user);

    @Delete("delete from user where id=#{id}")
    int delUser(@Param("id") int id);
}

测试类

【注意:我们必须要把mapper绑定到核心配置文件里】

8.4 关于@param注解
  • 方法存在多个参数(原生参数如string,如果是User这种定义对象的参数则不需要)
  • 如果只有一个基本类型,可以忽略,最好也加上
  • 所在参数必须加上@param注解,注解如果不与原参数同名,则在调用接口查询时也应同时更改
  • 我们在SQL中引用的就是我们这里的@Param设定的属性名⬇

#{}与${}区别

  • 尽量用#{},可以比较有效的防止sql注入
9. lombok

使用步骤

  1. idea装插件

  1. maven仓库
        
            org.projectlombok
            lombok
            1.18.12
        
  1. 在实体类上加注解
@Data

@AllArgsConstructor

@NoArgsConstructor

支持的种类

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system

常用:

@Data:无参构造,get,set,tostring,hashcode,eqals

@AllArgsConstructor:有参构造

@NoArgsConstructor

10. 多对一处理

多对一

  • 多个学生,对应一个老师
  • 对于学生而言,关联,多个学生关联一个老师
  • 对于老师而言,集合,一个老师有很多学生

SQL:

外键架构

create table `teacher`(
`id` int(10) not null,
`name` varchar(30) default null,
primary key(`id`)
)engine=INNODB default charset=utf8

insert into teacher(`id`,`name`) values(1,'TeacherQ');

create table `student`(
`id` int(10) not null,
`name` varchar(30) default null,
`tid` int(10) default null,
primary key(`id`),
key `fktid`(`tid`),
constraint `fktid` foreign key (`tid`) references `teacher`(`id`)
)engine=INNODB default charset=utf8

INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, '小明', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, '小红', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, '小张', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, '小李', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, '小王', 1);

测试环境搭建

  1. 导入lombok
  2. 新建实体类 Teacher,Student
  3. 建立mapper接口
  4. 建立mapper.xml文件
  5. 在核心配置文件绑定我们的mapper接口/文件【方式很多】
  6. 测试查询能否成功

错误解决

IDEA JUnit Test报错:3 字节的 UTF-8 序列的字节 2 无效

解决办法:

在总maven pom.xml中加入如下统一设置编码为UTF-8


    UTF-8

10.1 按照查询嵌套处理
    
        select * from student
    

    
        
        
        
        
    

    
        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=#{tid}
    
    
        
        
        
        
            
            
            
        
    

按查询嵌套处理

    
        select * from student where tid=#{tid}
    

小结

  1. 关联→association 【多对一】
  2. 集合→collection 【一对多】
  3. javaType & ofType
  • javaType用来指定实体类中属性的类型 例如:List
  • ofType用来指定映射到List或者集合当中的pojo类型,泛型中的约束类型 例如自定义的Student

注意点

  • 保证SQL语句的可读性,尽量保证通俗易懂
  • 注意一对多多对一中属性名字段的问题
  • 如果不好排查错误,可以使用日志,建议使用log4j
  • 尤其是resultmap/resulttype里的拼写一致和正确

慢查询 1s 1000s

面试必问

  • MySQL引擎

【整理】MySQL引擎

  • InnoDB底层原理

mysql存储引擎InnoDB详解,从底层看清InnoDB数据结构

  • 索引
  • 索引优化

MySQL索引

12. 动态SQL

什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

利用动态 SQL,可以彻底摆脱这种痛苦

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

搭建环境

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT 博客id,
`title` VARCHAR(100) NOT NULL COMMENT 博客标题,
`author` VARCHAR(30) NOT NULL COMMENT 博客作者,
`create_time` DATETIME NOT NULL COMMENT 创建时间,
`views` INT(30) NOT NULL COMMENT 浏览量
)ENGINE=INNODB DEFAULT CHARSET=utf8

创建一个基础工程

  1. 导包
  2. 编写配置文件
  3. 编写实体类
@Data
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
} 
  1. 编写实体类对应的mapper接口以及mapper.xml

有时候出现bug因为xml没有定位到实体类

IF

        select * from mybatis.blog
        
            
                
                    title=#{title}
                
                
                    author=#{author}
                
                
                    and views=#{views}
                
            
        
    
trim (where, set) where

        select * from mybatis.blog
        
            
        

注意事项:

  • 最好基于单表定义SQL片段
  • 不要存在where标签
foreach
    
        select * from mybatis.blog
        
            
                id=#{id}
            
        
    

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,根据SQL的格式,去排列组合就可以了

建议:

  • 先在MySQL写出完整的SQL语句再对应的写出动态SQL实现复用
13. 缓存 13.1 简介
查询:需要连接数据库,耗费资源
      一次查询的结果会暂存在一个可以直接取到的地方-->内存:缓存

再次查询相同数据时,会直接从缓存中取到结果,不需要再走数据库
  1. 什么是缓存?
  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率。解决了高并发系统的性能问题。
  1. 为什么使用缓存?
  • 减少和数据库交互的次数,减少系统开销,提高系统效率
  1. 什么样的数据能使用缓存?
  • 经常查询但不经常改变的数据【可以使用缓存】
13.2 Mybatis缓存
  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率
  • MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
  • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存!也成为本地缓存)
  • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存
  • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存
13.3 一级缓存
  • —级缓存也叫本地缓存
  • 与数据库同一次会话期间查询到的数据会放在本地缓存中
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库

测试步骤:

  1. 开启日志
  2. 在一个Session中查询两次相同的记录
  3. 查看日志输出

我们可以看到查询只进行了一次

缓存失效的情况:

  • 查询不同的记录

  • 进行增/删/改操作的时候,可能会改变数据,就会刷新缓存

  • 查询不同的mapper

  • 手动清除

小结:一级缓存默认是开启的,只在一次Sqlsession中有效,也就是拿到连接到关闭这个区间段

一级缓存就是一个map

13.4 二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存。

工作机制

  • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中。
  • 如果当前会话关闭了,这会话对应的一级缓存就没了,但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中。
  • 新的会话查询信息,就可以从二级缓存中获取内
  • 不同的mapper查出的数据会放在自己对应的缓存(map)中

步骤:

  1. 开启全局缓存(在配置文件中

  1. 在要使用二级缓存的mapper中开启

也可以自定义参数


  1. 测试

  2. 问题:我们需要将实体类序列化,否则会报错

小结:

  • 只要开启了二级缓存,在同一个mapper下就有效
  • 所有数据都会先缓存在一级缓存中
  • 只有当会话提交/关闭的时候,才会交到二级缓冲中
13.5 缓存原理

13.6 Ehcache缓存

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

要在程序中使用ehcache,先要导包

        
            org.mybatis.caches
            mybatis-ehcache
            1.1.0
        

ehcache.xml




    

    

    

在mapper中指定使用ehcache缓存实现

    

redis数据库做缓存 K-V

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/325357.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号