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

在IDEA2021-2中使用MyBatis

Java 更新时间:发布时间: 百科书网 趣学号

目录
  • 前言
  • 一、准备工作
    • 1、进入Mybatis官网
    • 2、新建maven空项目
    • 3、配置pom.xml
    • 4、新建module
    • 5、连接数据库
  • 二、配置mybatis相关
    • 1、新建mybatis-config.xml(核心配置文件)
    • 2、编写mybatis工具类
    • 3、实体类
    • 4、dao接口
    • 5、接口实现(xml映射文件)
    • 6、测试
  • 三、CRUD测试
    • 1、根据id查询用户
    • 2、增删改
    • 3、map
    • 4、模糊查询
  • 四、对配置文件的深度解析
    • 1、环境配置(environments)
    • 2、属性(properties)
    • 3、类型别名(typeAliases)
    • 4、设置(settings)
    • 5、映射器(mappers)
    • 6、作用域(Scope)和生命周期
  • 五、属性名和字段名不一致的解决方法
    • 1、在 SELECt 语句中给字段名起别名
    • 2、在xml中使用结果映射(resultMap)
  • 六、日志
    • 1、STDOUT_LOGGING(标准日志输出)
    • 2、LOG4J
  • 七、分页
    • 1、熟悉sql语句
    • 2、使用Offset /Fetch Next
    • 3、使用RowBounds
    • 4、分页插件(Mybatis PageHelper)
  • 八、使用注解开发
    • 1、新建module
    • 2、修改几个文件
    • 3、CRUD
  • 九、复杂查询环境搭建
    • 1、建表
    • 2、新建module并测试
    • 3、多对一的处理
    • 4、一对多的处理
  • 十、动态sql
    • 1、建表
    • 2、新建module
    • 3、if
    • 4、where
    • 5、choose、when、otherwise
    • 6、set
    • 7、trim
    • 8、foreach
    • 9、SQL片段
  • 十一、缓存

前言

我是跟随狂神的B站教学视频以及mybatis官网学习的,狂神B站传送门:https://www.bilibili.com/video/BV1NE411Q7Nx
喜欢看视频的直接去看就行了,讲的非常nice

用到的数据库表名user我改成了login,因为user是sql server关键字(老师用的mysql,我用的sql server)
其他步骤大致相同,相当于我的学习笔记,掺杂了一些个人见解
只想学基础增删改查的看完前三部分就行

我的学习顺序:MyBatis=>Spring=>SpringMVC=>SpringBoot
其他相关博客会陆续发布…

一、准备工作

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

1、进入Mybatis官网

传送门 https://mybatis.org/mybatis-3/zh/index.html
点击侧边栏中的 入门
可以看到在maven中的依赖代码

2、新建maven空项目


点击next,项目命名为mybatis

点击finish
删除src,方便新建module

3、配置pom.xml

1)导入三个依赖 mssql-jdbc、mybatis、junit

 
     
     
         com.microsoft.sqlserver
         mssql-jdbc
         9.4.0.jre16
     

     
     
         org.mybatis
         mybatis
         3.5.6
     

     
         junit
         junit
         4.12
     
     
 

2)再配置build中的resources节点,防止无法导出配置文件(所有pom文件都要做此修改)

 
        
        
            
                src/main/resources
                
                    ***.xml
                
                true
            
            
                src/main/java
                
                    ***.xml
                
                true
            
        
    
4、新建module

命名test

可以看到父子项目的依赖完全相同

5、连接数据库

连接名为test的数据库

二、配置mybatis相关 1、新建mybatis-config.xml(核心配置文件)




    
        
            
            
                
                
                
                
            
        
    

只要修改四处,把对应的value修改即可

2、编写mybatis工具类

新建MybatisUtils类

我们需要从 XML 中构建 SqlSessionFactory
再从 SqlSessionFactory 中获取 SqlSession

package com.jiyu.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;

    //1、从 XML 中构建 SqlSessionFactory
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //2、从 SqlSessionFactory 中获取 SqlSession
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

3、实体类

1)数据库建表login

增加数据

2)建立Login类

4、dao接口

新建LoginDao接口

接口中的方法

5、接口实现(xml映射文件)

一个sql语句既可以通过 XML 定义,也可以通过注解定义。
先看xml的方法
新建LoginMapper.xml(以后实现接口方法的xml文件都简称xml映射文件)





    
        select * from login where id=#{id}

3)在测试文件(LoginDaoTest.java)测试

@Test
    public void getLoginById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);

        Login login = mapper.getLoginById(1);
        System.out.println(login);

        sqlSession.close();
    }

结果正确

总结:增删改查都是三步:
1、编写接口中的方法
2、编写对应xml映射文件(要在核心配置文件中注册mapper),主要写sql语句
3、测试
但是增删改需要提交事务,代码有一点不同

2、增删改

增删改的步骤和查找一样,只是在测试时需要提交事务
下面直接贴代码

1)接口(LoginMapper.java)

package com.jiyu.dao;

import com.jiyu.entity.Login;

import java.util.List;

public interface LoginMapper {
    //查询全部用户
    List getLoginList();

    //根据id查询用户
    Login getLoginById(int id);

    //增加一个用户
    int addLogin(Login login);

    //修改用户
    int updateLogin(Login login);

    //删除一个用户
    int deleteLogin(int id);
}

2)xml映射文件(LoginMapper.xml)






    
        select * from login where id=#{id}
    

    
        insert into login (id,name,pwd) values (#{id},#{name},#{pwd})
    
    
    
        update login
        set name = #{name},pwd=#{pwd}
        where id=#{id};
    

    
        delete
        from login
        where id=#{id};
    

3)测试(LoginDaoTest.java)

package com.jiyu.dao;

import com.jiyu.entity.Login;
import com.jiyu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;


public class LoginDaoTest {
    @Test
    public void test(){
        //获得sqlSession
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //方法一:getMapper
        LoginMapper loginDao = sqlSession.getMapper(LoginMapper.class);
        List loginList = loginDao.getLoginList();

        //方法二:selectList(不太好)
        //List loginList = sqlSession.selectList("com.jiyu.dao.LoginDao.getLoginList");

        for(Login login:loginList){
            System.out.println(login);
        }

        //关闭sqlSession
        sqlSession.close();
    }

    @Test
    public void getLoginById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);

        Login login = mapper.getLoginById(1);
        System.out.println(login);

        sqlSession.close();
    }

    //增删改需要提交事务  sqlSession.commit()
    @Test
    public void addLogin(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);

        int res = mapper.addLogin(new Login(4, "zhaosi", "zhaosipass"));
        if(res>0){
            System.out.println("success!");
        }

        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void updateLogin(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);

        mapper.updateLogin(new Login(4,"zhaosisi","zhaosipass"));

        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void deleteLogin(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);

        mapper.deleteLogin(4);

        sqlSession.commit();
        sqlSession.close();
    }
}

3、map

数据库表的字段或者实体类参数过多,考虑使用map
map传参,在sql中取出key即可
对象传参,在sql中取出对象的属性即可
只有一个基本类型参数时,可以直接在sql中取到
多个参数用map或者注解

下面是两个例子
主要是利用map.put()方法建立一个map后,作为参数将多个数据传入sql

1、addLogin2:增加Login

1)接口

int addLogin2(Map map);

2)xml映射文件


        insert into login (id, name, pwd)
        values (#{userId},#{userName},#{password});

3)测试

@Test
    public void addLogin2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);

        Map map = new HashMap<>();

        map.put("userId",5);
        map.put("userName","wangwu");
        map.put("password","wangwupass");

        mapper.addLogin2(map);

        sqlSession.commit();
        sqlSession.close();
    }

2、getLoginById2:通过id获取Login

1)接口

    Login getLoginById2(Map map);

2)xml映射文件


        select * from login where name like #{value};

方法二(容易sql注入)


 select
   user_id             as "id",
   user_name           as "userName",
   hashed_password     as "hashedPassword"
 from some_table
 where id = #{id}

2、在xml中使用结果映射(resultMap)

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

直接使用官网的例子:

先定义一个resultMap(id是主键,result是普通的字段)


  
  
  

然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)


        select * from login

3)测试

@Test
   public void getLoginByRowBounds(){
       SqlSession sqlSession = MybatisUtils.getSqlSession();

       RowBounds rowBounds = new RowBounds(0, 2);//只需要改动这里的参数即可

       List loginList = sqlSession.selectList("com.jiyu.dao.LoginMapper.getLoginByRowBounds",null,rowBounds);
       for (Login login : loginList) {
           System.out.println(login);
       }

       sqlSession.close();
   }

在idea中可以看到两个参数的意义,其他两个文件写好后不需要改动

4、分页插件(Mybatis PageHelper)

官网传送门:https://pagehelper.github.io/
点击左上角 文档 即可查看使用教程,不做详细讲解

八、使用注解开发

映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

1、新建module

1)建立名为test02的module
以下几个文件都是复制test模块的,暂时未做修改

2、修改几个文件

未提及的文件都是和test模块一模一样,无需修改的

1)核心配置文件





    

    
        
    

    
        
    

    
        
            
            
                
                
                
                
            
        

        
            
            
                
                
                
                
            
        
    


    
        
    

2)接口

package com.jiyu.dao;

import com.jiyu.entity.Login;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface LoginMapper {
    @Select("select * from login")
    List getLogins();
}

3)测试
新建LoginMapperTest

import com.jiyu.dao.LoginMapper;
import com.jiyu.entity.Login;
import com.jiyu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class LoginMapperTest {
    @Test
    public void getLogins(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        List logins = mapper.getLogins();
        for (Login login : logins) {
            System.out.println(login);
        }

        sqlSession.close();
    }
}

运行结果

3、CRUD

先设置事务自动提交
在MybatisUtils.java中,给openSession方法添加参数true,表示自动commit

1)接口

package com.jiyu.dao;

import com.jiyu.entity.Login;
import org.apache.ibatis.annotations.*;

import java.util.List;
import java.util.Map;


public interface LoginMapper {
    @Select("select * from login")
    List getLogins();

    //方法存在多个参数,所有的参数前面必须加上@param("")注解
    @Select("select * from login where id=#{id}")
    Login getLoginById(@Param("id") int id);

    @Insert("insert into login(id,name,pwd) values(#{id},#{name},#{pwd})")
    int addLogin(Login login);

    @Update("update login set name=#{name},pwd=#{pwd} where id=#{id}")
    int updateLogin(Login login);

    @Delete("delete from login where id=#{uid}")
    int deleteLogin(@Param("uid") int id);//注解使用的是@Param("uid")中的uid而非该方法的参数id
}

2)测试

import com.jiyu.dao.LoginMapper;
import com.jiyu.entity.Login;
import com.jiyu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;


public class LoginMapperTest {
    @Test
    public void getLogins(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        List logins = mapper.getLogins();
        for (Login login : logins) {
            System.out.println(login);
        }

        sqlSession.close();
    }

    @Test
    public void getLoginById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        Login loginById = mapper.getLoginById(1);
        System.out.println(loginById);
        sqlSession.close();
    }

    @Test
    public void addLogin(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        mapper.addLogin(new Login(666,"test","testpass"));

        sqlSession.close();
    }

    @Test
    public void updateLogin(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        mapper.updateLogin(new Login(666,"test666","test666pass"));

        sqlSession.close();
    }

    @Test
    public void deleteLogin(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        mapper.deleteLogin(666);

        sqlSession.close();
    }
}
九、复杂查询环境搭建 1、建表

新建名为complex relationship的数据库
连接

接下来新建表
1)teacher

create table teacher
(
    id   int not null
        constraint teacher_pk
            primary key nonclustered,
    name nvarchar(30)
)

数据

2)student
外键:tid(对应teacher的id)

create table student
(
	id int not null
		constraint student_pk
			primary key nonclustered,
	name nvarchar(30),
	tid int
		constraint student_teacher_id_fk
			references teacher
				on update cascade on delete cascade
)

数据

可以查看两张表的关系

2、新建module并测试

1)建立module:test03
2)module中的文件:(数字代表建立的顺序)

下面是所有文件的代码,用数字表示文件名
1、

driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:sqlserver://localhost:1433;databaseName=complex relationship
username=sa
password=123456

2、(mappers部分在建立了两个接口文件后再写进去)





    

    
        
    

    
        
        
    

    
        
            
            
                
                
                
                
            
        

        
            
            
                
                
                
                
            
        
    

    
        
        
    

3、

package com.jiyu.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;

    //1、从 XML 中构建 SqlSessionFactory
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //2、从 SqlSessionFactory 中获取 SqlSession
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
    }
}

4、

package com.jiyu.entity;

public class Teacher {
    private int id;
    private String name;

    public Teacher(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Teacher() {
    }

    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;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + ''' +
                '}';
    }
}

5、

package com.jiyu.entity;

public class Student {
    private int id;
    private String name;
    private Teacher teacher;//关联老师

    public Student() {
    }

    public Student(int id, String name, Teacher teacher) {
        this.id = id;
        this.name = name;
        this.teacher = teacher;
    }

    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 Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", teacher=" + teacher +
                '}';
    }
}

6、

package com.jiyu.dao;

import com.jiyu.entity.Teacher;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface TeacherMapper {

    @Select("select * from teacher where id=#{tid}")
    Teacher getTeacher(@Param("tid") int id);
}

7、

package com.jiyu.dao;

public interface StudentMapper {
}

8、







9、







10、

import com.jiyu.dao.TeacherMapper;
import com.jiyu.entity.Teacher;
import com.jiyu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class MyTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);


        sqlSession.close();
    }
}

运行结果

至此说明基本的环境已经配置好了

3、多对一的处理

目的:查询所有的学生信息,以及对应的老师的信息
对应sql语句:

select s.id,s.name,t.name from student s,teacher t where s.tid=t.id

但是该语句涉及到了两个实体(多表查询),所以在xml映射文件中不能仅通过简单的一句sql来实现

1、先看问题的引入:select * from student

1)接口(StudentMapper)

public List getStudent();

2)xml映射文件


        select * from student
    

3)测试

 @Test
   public void testStudent(){
       SqlSession sqlSession = MybatisUtils.getSqlSession();
       StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
       List students = mapper.getStudent();
       for (Student student : students) {
           System.out.println(student);
       }

       sqlSession.close();
   }

结果:
出现了teacher=null的情况(因为对象的属性和表中的字段没有对应)
这个时候就需要一个对teacher的查询

2、解决方法一:嵌套 Select 查询(类似sql中的嵌套查询)

1)接口:不变
2)xml映射文件:
修改为


        select * from teacher where id=#{id}
    

association那一行表示:
在查询学生时,字段tid映射为teacher,并且是一个对象,对象类型为Teacher,这个对象需要使用一个select语句,对应的查询语句id为getTeacher

在官网对select的解释:

所以,column中的tid会作为参数传递给查询语句的大括号中的“id”,实际上,无论大括号内写什么,都不会影响最后的效运行结果,因为他的参数只取决于column的属性

3)测试:不变
直接运行

3、解决方法二:相当于联表查询(较为简单)

1)接口:

    public List getStudent2();

2)xml映射文件

	
        select * from teacher
 

3)测试

public class MyTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List teachers = mapper.getTeacher();
        for (Teacher teacher : teachers) {
            System.out.println(teacher);
        }

        sqlSession.close();
    }
}

结果:

可以看到students=null

3、解决方法

先用sql查询

1)接口

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

2)xml映射文件

	
        select * from blog where 1=1
        
            and title=#{title}
        
        
            and author=#{author}
        
    

3)测试

 @Test
    public void queryBlogIF(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();
        List blogs = mapper.queryBlogIF(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

运行结果:

因为传入的map为空,所以sql语句相当于select * from blog

当在测试文件加上这句代码,修改map后

运行结果:
此时sql相当于select * from blog where title='Java如此简单'
所以只能查到一条数据
如果修改成下面这样,那么sql相当于select * from blog where author='jiyu'

4、where

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

1)接口

    List queryBlogWhere(Map map);

2)xml映射文件

	
        select * from blog
        
            
                 title=#{title}
            
            
                and author=#{author}
            
        
    

3)测试

@Test
    public void queryBlogWhere(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();
         map.put("title","Java如此简单");
//        map.put("author","jiyu");

        List blogs = mapper.queryBlogWhere(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }
5、choose、when、otherwise

官网的简介非常清楚
相当于switch case default

用法如下:
1)接口

    List queryBlogChoose(Map map);

2)xml映射文件