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

Mybatis笔记

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

Mybatis笔记

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

持久层就是完成持久化工作的代码块

  • 数据持久化:将程序的数据在持久状态和瞬时状态转化的过程

    • 数据库
    • io文件持久化
  • 持久化的作用

    • 储存要保存下来的数据
    • 降低成本(内存成本高)
MyBatis作用
  • 方便
  • 容易上手
  • 简化传统的JDBC代码,形成框架,自动化
  • 帮助程序员将数据存入到数据库中
  • 优点:
    • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
    • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
    • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql。
MyBatis获取
  • Github获取 :地址

  • Maven仓库:地址

    
        org.mybatis
        mybatis
        3.5.7
    
    
  • 中文文档:地址

MyBatis详执行流程 第一个MyBatis程序

**思路:**搭建环境->MyBatis->编写代码->测试

1.创建目录&导包 (搭建环境)
  • 新建数据表

  • 创建Maven项目,删除src作为父工程

  • 导入jar包 Maven仓库

    
    
        4.0.0
    
        org.example
        testMybatis
        1.0-SNAPSHOT
    
        
            15
            15
        
    
    
        
            
            
            
                org.mybatis
                mybatis
                3.5.7
            
    
            
            
            
                mysql
                mysql-connector-java
                8.0.12
            
    
    
            
            
            
                junit
                junit
                4.13.2
                test
            
    
        
    
    
  • 创建子模块

2.编写MyBatis工具类 方法一

从XML中构建SqlSessionFactory

  • 编写配置文件



    



        
            
            
                

                
                
                
            
        



        
            
            
                
                
                
                
            
        
    
    

        
    

  • 在until中编写工具类
package utils;

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;

public class MyBatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        //配置文件url
        String resource = "mybatis-config.xml";
        try {
            //使用MyBatis获取sqlSessionFactory工具类
            InputStream in = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

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

方法二

直接使用java代码

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
3.编写代码
  • 编写实体类

    package pojo;
    
    public class User {
        private int id;
        private String name;
        private String password;
    
        public User() {
        }
    
        public User(int id, String name, String password) {
            this.id = id;
            this.name = name;
            this.password = password;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + ''' +
                    ", password='" + password + ''' +
                    '}';
        }
    }
    
    
  • Dao接口

    package dao;
    
    import pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        List getUserList();
    
    
    }
    
    
  • 接口实现类由原来的UserDaoImpl转变为一个Mapper配置文件

    
    
    
    
    
        
            select * from user where id = #{id}
        
    
增删改要提交事务!
sqlSession.commit();
insert增
@Test
    public void addUser(){
        //1.获得SqlSession对象
        SqlSession sqlSession =  MyBatisUtils.getSqlSession();
        //2.执行SQL
        try{
            //方法一: getMapper 最新(推荐)
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            int res = userMapper.addUser(new User(4,"wzf","44444"));
            if(res>0){
                System.out.println("插入成功!");
            }

            //提交事务
            sqlSession.commit();
        }finally {
            //3.关闭sqlSession
            sqlSession.close();
        }
    }

        insert into user (id,name,password) values(#{id},#{name},#{password})
    
update改
 @Test
    public void updateUser(){
        //1.获得SqlSession对象
        SqlSession sqlSession =  MyBatisUtils.getSqlSession();
        //2.执行SQL
        try{
            //方法一: getMapper 最新(推荐)
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            int res = userMapper.updateUser(new User(4,"wzf","23333"));
            if(res>0){
                System.out.println("修改成功");
            }

            //提交事务
            sqlSession.commit();
        }finally {
            //3.关闭sqlSession
            sqlSession.close();
        }
    }

        update user set name=#{name},password=#{password} where id=#{id}
    
delete删
@Test
    public void deleteUser(){
        //1.获得SqlSession对象
        SqlSession sqlSession =  MyBatisUtils.getSqlSession();
        //2.执行SQL
        try{
            //方法一: getMapper 最新(推荐)
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            int res = userMapper.deleteUser(4);
            if(res>0){
                System.out.println("删除成功");
            }

            //提交事务
            sqlSession.commit();
        }finally {
            //3.关闭sqlSession
            sqlSession.close();
        }
    }

        delete from user where id=#{id}
    
自定义值名称方法Map
  • 接口
int addUser2(Map map);
  • 配置文件
	
        insert into user (id,name,password) values(#{userId},#{userName},#{userPassword})
                                                    
    
  • 测试程序
@Test
    public void addUser2(){
        //1.获得SqlSession对象
        SqlSession sqlSession =  MyBatisUtils.getSqlSession();
        //2.执行SQL
        try{
            //方法一: getMapper 最新(推荐)
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            Map map = new HashMap<>();

            map.put("userId",4);
            map.put("userName","wzf");
            map.put("userPassword","111111");

            int res = userMapper.addUser2(map);
            if(res>0){
                System.out.println("添加成功");
            }

            //提交事务
            sqlSession.commit();
        }finally {
            //3.关闭sqlSession
            sqlSession.close();
        }
    }
多个参数 方法一 使用Map封装数据
  • 接口
List getUser(Map map);
  • 配置文件

        select * from user where id=#{id} and name=#{name}
    
  • 测试代码
 @Test
    public void getUser1() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();

        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List userList = userMapper.getUser1(4,"wzf");

            for (User temp: userList
            ) {
                System.out.println(temp);
            }
        } finally {
            sqlSession.close();
        }
    }
模糊查询
  • 接口
	//近似查询用户
    List getLikeUser(String name);
  • 配置文件
	
        SELECT * FROM student
    
    
        
        

        
        
    


    
        SELECT s.id sid,s.name sName,t.name tName
        FROM student s,teacher t
        WHERe s.tid=t.id;
    
    
        
        
        
            
        

  • 测试
@Test
    public void testGetStudent2(){
        try(SqlSession sqlSession = MyBatisUtils.getSqlSession()){
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            List studentList = studentMapper.getStudent2();
            for (Student student : studentList) {
                System.out.println(student);
            }
        }
    }
  • 流程

    • 调用getStudent2接口

    • 执行组合查询语句(sql中给各字段取别名,区分相同字段)

    • 进行结果集映射

    • 将Teacher作为一个类映射回去

    • 在Teacher内部再进行结果集映射

  • 原理

    • 在结果集映射中,使用association标签,将每条记录有关于teacher的信息封装成一个类返回
    • 即将查询出来的有关Teacher的字段一一对应Teacher类中的内容,然后将这个Teacher类返回
一对多处理 实体类
package pojo;

import lombok.Data;

@Data
public class Student02 {
    private int id;
    private String name;
    private int tid;

}

package pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher02 {
    private int id;
    private String name;

    //一个老师多个学生
    private List students;
}

方式一:按照查询嵌套处理
  • 接口
List getTeacher2(@Param("tid")int tid);
  • 配置文件
	
        SELECT * FROM student WHERe tid=#{tid}
    
  • 测试
@Test
public void testGetTeacher2(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    try{
        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        List teacher = teacherMapper.getTeacher2(1);
        for (Teacher02 teacher02 : teacher) {
            //
            System.out.println(teacher02);
        }
    }finally {
        sqlSession.close();
    }
}
  • 流程同多对一方法一
方式二:按照结果嵌套处理
  • 接口
List getTeacher(@Param("tid")int tid);
  • 配置文件.xml

        SELECT * FROM blog WHERe 1=1
        
            and title = #{title}
        
        
            and author = #{author}
        
    
  • 测试
    @Test
    public void queryBlog(){
        try(SqlSession sqlSession = MyBatisUtils.getSqlSession()){
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            Map map = new HashMap();
            map.put("title","title");
            //map.put("author","wzf");

            List blogList = blogMapper.queryBlog(map);

      for (Blog blog : blogList) {
        //
        System.out.println(blog);
      }
        }
    }
Where标签

作用:

  • 自动判断是否使用Where语句(当Where标签中的条件均不成立时不添加Where语句)
  • 自动省略第一个AND或OR

例:


        SELECT * FROM blog
        
            
                id=#{id}
            
        
    
  • 测试
 @Test
  public void queryBlogForeach(){
    try(SqlSession sqlSession=MyBatisUtils.getSqlSession()){
      BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
      Map> map = new HashMap<>();
      ArrayList arrayList= new ArrayList<>();
      arrayList.add(1);
      arrayList.add(2);
      arrayList.add(3);
      arrayList.add(4);
      arrayList.add(5);
      map.put("ids",arrayList);
      List blogList = blogMapper.queryBlogForeach(map);
      for (Blog blog : blogList) {
        System.out.println(blog);
      }
    }
  }
  • 通过foreach将sql拼成:SELECT * FROM blog WHERe ( id=1 OR id=2 OR id=3 OR id=4 OR id=5 )的形式
缓存

缓存:

  • 将查询的数据暂存在内存中

  • 再次查询相同的数据时,直接找缓存,提高查询效率

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

Mybatis缓存
  • Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
    • 为了提高拓展性,MyBatis定义了缓存接口Cache,可以通过实现Cache接口来自定义二级缓存
一级缓存
  • 一级缓存也叫本地缓存:SqlSession级别
    • 与数据库同一次会话期间查询到的数据会放在本地缓存中
    • 以后如果需要获取相同的数据,直接从缓存中拿,不用再去查询数据库

在sqlsession开启和关闭之间有效

  • 有效情况

    • 映射语句文件中的所有select语句的结果将会被缓存
  • 失效情况

    • 映射语句文件中所有的insert,update和delete语句将会刷新缓存
    • select语句的内容不同
  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。

  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。

  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。

  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

测试 测试一:连续进行两次查询
  • 代码:
 @Test
  public void queryBlog() {
    try (SqlSession sqlSession = MyBatisUtils.getSqlSession()) {
      BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
      Map map = new HashMap<>();
      map.put("title", "title1");
      // map.put("author","wzf");
      //第一次查询
      List blogList = blogMapper.queryBlog(map);
      for (Blog blog : blogList) {
        System.out.println(blog);
      }
      //第二次查询
      List blogList1 = blogMapper.queryBlog(map);
      for (Blog blog : blogList1) {
        System.out.println(blog);
      }
    }
  }
  • 结果: 进行两次查询,但只与数据库进行一次连接

测试二:在两次查询中夹杂一次增添操作
  • 代码:
  @Test
  public void queryBlog() {
    try (SqlSession sqlSession = MyBatisUtils.getSqlSession()) {
      BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
      Map map = new HashMap<>();
      map.put("title", "title1");
      // map.put("author","wzf");
      //第一次查询
      List blogList = blogMapper.queryBlog(map);
      for (Blog blog : blogList) {
        System.out.println(blog);
      }

      //在两次查询之间插入更新语句
      this.addBlog();

      System.out.println("=======================");
      //第二次查询
      List blogList1 = blogMapper.queryBlog(map);
      for (Blog blog : blogList1) {
        System.out.println(blog);
      }
    }
  }
  • 结果: 与数据库进行了两次连接

  • 原因:当对数据库中的内容进行增删改以后,数据库内容改变了,为了保证数据是最新的,所有必须重写查询
手动清理缓存
sqlSession.clearCacher();	//手动清理缓存

小结:
  • 一级缓存默认开启
  • 只在一次SqlSession中有效
作用:
  • 加速同一用户的数据库操作
二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所有诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存(在同一个mapper中)
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 会话关闭时,以及缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
开启方式:
  1. 显示的开启全局缓存

在mybatis-config.xml中显示的开启cacherEnabled设置


作用:↑方便他人阅读你的代码,知道你使用了缓存

  1. 在mapper文件中加入


    
    
        INSERT INTO blog (id,title,author,create_time,views)
        VALUES (#{id},#{title},#{author},#{createTime},#{views})
    

标签属性

eviction(清除策略)
  • LRU – 最近最少使用:移除最长时间不被使用的对象。 (默认)
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
flushInterval(刷新间隔)

属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

size(引用数目)

属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。

readOnly(只读)

只读的缓存会给所有调用者返回缓存对象的相同实例

测试
  • 代码:
@Test
  public void test() {
    SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
    SqlSession sqlSession2 = MyBatisUtils.getSqlSession();

    BlogMapper mapper1 = sqlSession1.getMapper(BlogMapper.class);


    Map map = new HashMap<>();
    map.put("title", "title1");
    // map.put("author","wzf");

    List blogList = mapper1.queryBlog(map);
    for (Blog blog : blogList) {
      System.out.println(blog);
    }
    sqlSession1.close();  //会话关闭
    //此时一级缓存将内容放入二级缓存中后,一级缓存失效



    //在不同的SqlSession中仍能使用缓存中的内容(前提:必须在同一个mapper中)
    BlogMapper mapper2 = sqlSession2.getMapper(BlogMapper.class);
    System.out.println("=======================");

    List blogList1 = mapper2.queryBlog(map);
    for (Blog blog : blogList1) {
      System.out.println(blog);
    }
    sqlSession2.close();
  }
  • 结果: 只连接一次数据库

△注意

当cache中不写参数时要将java类序列化

package pojo;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.Objects;

@Data
public class Blog implements Serializable {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;

    public Blog(String id, String title, String author, Date createTime, int views) {
        this.id = id;
        this.title = title;
        this.author = author;
        this.createTime = createTime;
        this.views = views;
    }
}

小结:
  • 只要开启了二级缓存,在同一个mapper下就有效
  • 所有数据都会先放在一级缓存中;
  • 只有当会话提交或者结束时,才会提交到二级缓存中
select标签中可设置是否开启缓存/刷新缓存

update/delete/insert标签中可设置是否刷新缓存
    	
        UPDATE blog
        
            
        
        WHERe id = #{id}
    
缓存原理

自定义缓存-ehcache

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

  • 导包


    org.mybatis.caches
    mybatis-ehcache
    1.2.1

  • 使用自定义/第三方缓存

在cache中添加type属性


自己写的缓存实现
  • 实现Cache接口
package utils;

import org.apache.ibatis.cache.Cache;

import java.util.concurrent.locks.ReadWriteLock;

public class MyCache implements Cache {
    @Override
    public String getId() {
        return null;
    }

    @Override
    public void putObject(Object o, Object o1) {

    }

    @Override
    public Object getObject(Object o) {
        return null;
    }

    @Override
    public Object removeObject(Object o) {
        return null;
    }

    @Override
    public void clear() {

    }

    @Override
    public int getSize() {
        return 0;
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return Cache.super.getReadWriteLock();
    }
}

  • 一般不自己实现(现在常用redis来实现)
第三方缓存Ehcache 配置文件

在resource文件夹下创建一个ehcache.xml的配置文件




    
    

    

    



  
name                         缓存名称
maxElementInMemory           缓存最大数目
maxElementsonDisk            硬盘最大缓存个数
eternal                      对象是否永久有效,一旦设置了,timeout将不起作用
overflowToDisk               是否保存到磁盘,当系统宕机时
timeToleSeconds              设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false 即对象不是永久有效是使用,可选属性,默认值为0
timeToLiveSeconds            设置对象在失效前的允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false 即对象不是永久有效是使用,可选属性,默认值为0
diskPersistent				 是否缓存虚拟机重启期数据
diskSpoolBufferSizeMB		 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds	磁盘失效线程运行时间间隔,默认是120秒
memoryStoreEvictionPolicy	 当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用的原则)
		↑可选策略还有:FIFO(先进先出),LFU(最少访问次数),LRU(最近最少使用,默认策略)
clearonFlush				 内存数量最大时是否清除.

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

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

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