MyBatis学习笔记

 

配置解析

1.核心配置

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息

configuration(配置)

  • properties(属性)

  • settings(设置)

  • typeAliases(类型别名)

  • typeHandlers(类型处理器)

  • objectFactory(对象工厂)

  • plugins(插件)

  • environments(环境配置)

    • environment(环境变量)

      • transactionManager(事务管理器)

      • dataSource(数据源)

  • databaseIdProvider(数据库厂商标识)

  • mappers(映射器)

2.环境配置(environments)

 在xml中,所有的标签都有其顺序,不可打乱
 properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?

MyBatis 可以配置成适应多种环境

尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

每个数据库对应一个 SqlSessionFactory 实例

 
     
         
         
     
         
             
             
             
             
             
         
     
 

3.属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换

 driver=com.mysql.cj.jdbc.Driver
 url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
 username=root
 password=123
 
      
 
         
   

4.类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字, 意在降低冗余的全限定类名书写

 
 
 
 

通过包来取别名,默认为这个类的类名,不分大小写,建议用小写

 
 
 

可以通过注解来更改别名,不建议使用这种方式

 @Alias("test")
 public interface UserDao {

5.映射器(mappers)

     
     
     
         
     
     
     
     
     
       
     
       包注入同上
        

6.作用域(Scope)和生命周期

 

作用域、生命周期类别是童年的,因为错误的使用会导致非常严重的并发问题

SqlSessionFactoryBuilder:

  1. 创建创作了SqlSessionFactory,就不再需要它了,因此SqlSessionFactoryBuilder实例的最佳作用是作用域(也就是局部方法方法)。

SqlSessionFactory:

  1. 数据库连接池

  2. SqlSession 应用游戏被创建就应该在运行整个过程中一直存在,没有任何环境破坏或创建另一个实例。

  3. 因此SqlSessionFactory 的最佳作用域是应用作用域。 04. 最简单的就是使用单例模式或者静态单例模式。

SqlSession:

  1. 连接到连接池的一个请求;

  2. 每个线程都应该有它自己的SqlSession实例。SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳作用是域或方法作用域。绝对不能将SqlSession实例的引用放出在一个类的动态域,甚至一个类的实例变量也不行。

  3. 用完后需要关闭,否则资源被占用。

     try (SqlSession session = sqlSessionFactory.openSession()) {
       // 你的应用逻辑代码
     }

 

在所有代码中都遵循这种使用模式,可以保证所有数据库资源都被正确地关闭。

这里的每个Mapper,就代表一个具体的业务!

分页

使用Limit分页

使用Mybatis实现分页,核心是SQL

 语法:select * from mybatis.user limit indexpage,pageSize
         select * from mybatis.user limit 3 【0,3】

实现

1.在接口内编写方法,使用map传递参数

 List getLimit(Map map);

2.实现方法

     
     
         
         
      
 ​
 

3.测试代码

  @Test
     public void Limit(){
         SqlSession sqlSession = MyBatisUtil.getSqlSession();
         UserMapper mapper = sqlSession.getMapper(UserMapper.class);
         HashMap map = new HashMap();
         map.put("startIndex",0);
         map.put("PageSize",2);
         List limit = mapper.getLimit(map);
         for (User user: limit){
             System.out.println(user);
         }
         sqlSession.close();
     }

RowBounds分页

不再使用SQL实现分页

接口

     //使用RowRounds实现分页
     List getRowBounds();

实现

    

测试

 ​
     @Test
     public void getRowBounds(){
         SqlSession sqlSession = MyBatisUtil.getSqlSession();
         //RowBounds实现
         RowBounds rowBounds = new RowBounds(0, 2);
         //基于java代码实现分页
         List us = sqlSession.selectList("com.liu.dao.UserMapper.getRowBounds", null, rowBounds);
         for (User user:us){
             System.out.println(user);
         }
         sqlSession.close();
     }

使用注解开发

CRUD

1.注解在接口上实现

     @Select("select * from mybatis.user")
     List gtelist();
 ​
     //方法存在多个参数,所有参数前面必须加上@Param注解
     @Select("select * from mybatis.user where id = #{id}")
     User ById(@Param("id") int id);
     
      @Insert("insert into mybatis.user(id,username,pwd) values(#{id},#{username},#{pwd})")
     int add(User user);
    
     @Delete("delete from mybatis.user where id = #{id}")
     int del(@Param("id") int id);
 ​
      @Update("update mybatis.user set username=#{username},pwd=#{pwd} where id=#{id}")
     int upd(User user);

关于@Param()注解

基本类型的参数或者String类型的参数需要加上

引用类型不需要加

如果只有一个基本类型的话,可以忽略,但是建议加上

我们在Sql中引用的,就是@param中设置的属性名

2.需要在核心配置文件中绑定接口

注意:我们必须要将接口绑定到我们的核心配置文件中

    
         
     

3.测试

 public void list(){
 SqlSession sqlSession = MyBatisUtil.getSqlSession();
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 //查询
 List gtelist = mapper.gtelist();
 for (User user : gtelist) {
 System.out.println(user);
 }
 ​
 //按ID查询
 User user = mapper.ById(2);
 System.out.println(user);
 ​
 //修改
 mapper.upd(new User(9,"周怡","666999"));
 ​
 //删除
 mapper.del(10);
 ​
 //添加
 mapper.add(new User(10,"周怡","666"));
 ​
 sqlSession.close();
 }

本质:反射机制实现

底层:动态代理

 public static SqlSession getSqlSession(){
     //开启自动提交事务
     return sqlSessionFactory.openSession(true);
 }

Lombok

Project Lombok是一个java库,它可以自动插入编辑器和构建工具,为java增添乐趣。永远不要再编写另一个getter或equals方法,只要有一个注释,您的类就有一个功能齐全的构建器、自动记录变量等等。

使用步骤

1.在IDEA中安装Lombok插件

2.在项目中导入Lombok的jar包



    org.projectlombok
    lombok
    1.18.20
    provided

3在实体类上加注解

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
    private int id;
    private String username;
    private String pwd;
}
 @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
 Code inspections
 Refactoring actions (lombok and delombok)

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

@AllArgsConstructor:有参构造

@NoArgsConstructor:无参构造

多对一

 

多个学生,对应一个老师

对学生而言,关联,多个学生,关联一个老师【多对一】

对老师而言,集合,一个老师,又很多学生,【一对多】

 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, '秦老师'); 
 teacher
 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=utf8INSERT 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);

 

Mybatis核心配置中结果映射(resultMap)

 

测试环境搭建

1.导入Lombok

2.新建实体类

3.建立Mapper接口

4.建立Mapper.xml文件

5.在核心配置文件中绑定注册我们的Mapper或者xml文件

6.测试查询是否成功

按照查询嵌套处理

实体

 private int id;
 private String name;
 //多个学生关联一个老师
 private Teacher teacher;

 

接口

 List getStudent();

实现

 
 
 ​
 
 
 
 
 
     
 
 
 ​
 

按照结果嵌套处理

实现








    

    

    

回顾多对一查询方式

  • 子查询

  • 联表查询

一对多

按照结果嵌套处理

实体类

    private int id;
    private String name;
    //一个老师拥有多个学生
    private List students;

接口

 Teacher getTeacher(@Param("tid") int id);

实现






    
    
    
    
    
        
        
        
    
 

按照查询嵌套处理

实体和方法不变

  1. 关联 - association 多对一

  2. 集合 - collection 一对多

  3. javaType & ofTyp

  4. javaType用来指定实体类中属性的类

  5. ofType用来指定映射到List 或者集合中的pojo类型,泛型中的约束类型

实现

 
 ​
 ​
 
     
     
 
 ​
 ​
 

动态SQL

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

环境搭建

 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

实体

 import java.util.Date;
 @Data
 public class Blog {
     private String id;
     private String title;
     private String author;
     private Date createTime;//属性名和字段名不一致create_time
     private int views;
 }
     
         

ID工具类

 public class IDUtils {
 public static String getID(){
 return UUID.randomUUID().toString().replaceAll("-","");
 }

IF(test)

接口

     List queryBlog(Map map);

实现

  

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

测试

 @Test
 public void query(){
     SqlSession sqlSession =                             MyBatisUtil.getSqlSession();
     BlogMapper mapper =                                  sqlSession.getMapper(BlogMapper.class);
     HashMap map = new HashMap();
     //map.put("title","CRUD");
     map.put("author","%十%");
     mapper.queryBlog(map);
     sqlSession.close();
 }

Choos(when、otherwise)

 

Update( set,if,test )

使用Map传参

 
         update mybatis.blog
     
         
             title=#{title},
         
         
             author=#{author}
         
     
     where id=#{id}
 

trim

指定前缀,去除AND和OR

 
   ...
 

指定后缀,去除逗号

 
   ...
 

所谓的动态SQL,本质上还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

Foreach

格式

item 集合项

index 索引

collection 指定需要遍历的集合

open 拼接头的字符串

close 拼接尾的字符串

separator 分隔符

 

案例

SQL语句

 select * from mybatis.blog where (id=1 or id=2 or id=3)

接口

 List BlogForeach(Map map);

 

实现

 

测试

 public void Foreach(){
     SqlSession sqlSession = MyBatisUtil.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
     HashMap map = new HashMap();
     ArrayList list = new ArrayList();
     list.add(2);
     map.put("list",list);
     List blogs = mapper.BlogForeach(map);
     for (Blog blog : blogs) {
         System.out.println(blog);
     }
     sqlSession.close();
 }

SQL片段

有时候,我们会将一部分一些功能的部分抽取出来,方便复用

1.使用SQL标签抽取需要复用的部分

 
     
         
             title =#{title}
         
         
             and author=#{author}
         
         
             views=#{views}
         
     
 

2.在需要使用的地方使用include标签引用即可

 

主要事项

  • 最好基于单标来定义SQL片段

  • 不要存在where标签

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

缓存

简介

  • 查询:连接数据库,秏资源

  • 一次查询的结果,给它暂存到可以直接取到的地方---->内存:缓存

  • 我们再次查询相同数据的时候,直接走缓存,就不用走数据库了

1.什么是缓存?

  • 存在内存中的临时数据

  • 将用户经常查询的数据放在缓存中,用户去查询数据就不用从数据库中查询,而是从缓存中查询,提高查询效率,解决高并发系统的性能问题

2.为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率

3.什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据

MyBatis缓存

MyBatis包含了一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存,缓存可以极大的提升查询效率

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

  • 默认情况下,只有一级缓存开启(sqlsession级别的缓存,也称为本地缓存)

  • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存

  • 为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存

一级缓存

一级缓存也叫本地缓存:sqlsession

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中

  • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

测试

  1. 开启日志

  2. 测试再一次session中查询两次相同的记录

     @Test
     public void query(){
         SqlSession sqlSession = MyBatisUtil.getSqlSession();
         UserMapper mapper = sqlSession.getMapper(UserMapper.class);
         User user = mapper.queryById(1);
         System.out.println(user);
         System.out.println("===============================");
         User user1 = mapper.queryById(1);
         System.out.println(user1);
         sqlSession.close();
     }
  3. 查看日志输出:SQL语句只走了一次,第二次的数据是直接从Sqlsession中获取的

 

缓存失效的情况

  1. 查询不同的数据

  2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存

  3.  

  4. 查询不同的Mapper

  5. 手动清理缓存

 sqlSession.clearCache();//手动清理缓存

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

二级缓存

 

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

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

工作机制

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

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

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

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

步骤:

  1. 开启全局缓存

     
     
  2. 在要使用二级缓存的Mapper中开启二级缓存

         
         

    也可以在里面自定义一些参数

     
  3. 测试

      public void Two(){
             //创建两个sqlsession对象,执行同一个方法查询同一条数据,当第一个sqlsession缓存关闭的时候
             //一级缓存中的数据会被保存到二级缓存中,下一个方法可以直接从缓存中获取数据
             SqlSession sqlSession = MyBatisUtil.getSqlSession();
             UserMapper mapper = sqlSession.getMapper(UserMapper.class);
             User user = mapper.queryById(9);
             System.out.println(user);
             sqlSession.close();
     ​
             SqlSession sqlSession2 = MyBatisUtil.getSqlSession();
             UserMapper mapper2= sqlSession2.getMapper(UserMapper.class);
             User user2 = mapper2.queryById(9);
             System.out.println(user2);
             System.out.println(user==user2);
             sqlSession2.close();
         }

    序列化实体类,有时候会报错

     

     public class User implements Serializable

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效

  • 所有的数据都会先放在一级缓存中

  • 只有当会话提交,或者关闭的时候,才回提交到二级缓存中去

第一次写博客,随便写写,记录一下之前学习MyBatis时候的笔记,还有一点稍候补上

你可能感兴趣的:(mybatis,java,数据库,sql,mysql)