Mybatis学习笔记


1、搭建环境

1.1 搭建数据库

以个人为例,在WampServer中的MySQL创建mybatis数据库,同时创建mybatis表

1.2 创建Maven项目(模块)

1.3 导入依赖

在pom.xml的dependencies中加入以下代码。

如果在父项目的pom.xml中添加以下依赖,那么在子项目中即可使用,无需再次添加。

是否需要将依赖写在父项目或者子项目中,视情况而定。


    
    
        mysql
        mysql-connector-java
        8.0.19
    

    
    
        org.mybatis
        mybatis
        3.5.6
    

    
    
        junit
        junit
        4.13
    

1.4 添加核心配置文件

在模块中的resource文件夹下添加mybatis-config.xml,并写入以下代码

<?xml version="1.0" encoding="UTF8" ?>


    
        
            
            
                
                
                
                
            
        
    
    
        
        
        
        
        
        
    

  • url、username、password视情况修改
  • 对于每一个新创建的mapper的xml文件,都需要在mappers标签下进行注册,格式如上所示。
  • 为了避免引用错误,尽量将Mapper文件写在Resource文件夹下

2、SqlSession工具类创建

  • 这个工具类主要用于对SqlSessionFactory的初始化配置
package mybatis;

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 Utils {

    private static SqlSessionFactory sqlSessionFactory;

    // 初始化Mybatis配置
    static {
        try {
            String resource = "mybatis-config.xml";	// 配置文件名,可更改
            InputStream inputStream = Resources.getResourceAsStream( resource );
            sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
        } catch ( IOException e ) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

3、创建实体类

  • 实体类根据需求创建
  • 一般包含的元素与数据库表中的字段一一对应。
package pojo;

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

    public User() {
    }

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

    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 "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

3、编写接口

  • 根据业务需求,编写所需要的业务方法
package mybatis;

import org.apache.ibatis.annotations.Param;
import pojo.User;

import java.util.List;

public interface userMapper {

    List< User > getUserList();

    void insertUser( @Param( "user" ) User user );

    void deleteUser( int id );

    void updateUser( @Param("id") int id, @Param("name") String name );
}

4、编写接口Mapper.xml

  • 这个xml文件的作用于接口实现类的作用相同,只是Mybatis将JDBC代码省略,我们只需写出相应的sql语句即可

  • namespace里面放的是接口名(全限定名)

  • 每个标签里面的 id 对应 方法名

  • resultType可以放实体名(全限定名)和String等类型

  • Mapper写完之后记得在配置文件 config.xml 中注册

  • 参数类型需要在接口方法参数中通过注解@param来进行配置

<?xml version="1.0" encoding="UTF-8" ?>




    

    
        insert into user(id, user) values(#{user.id}, #{user.name})
    

    
        delete from user where id = #{id}
    

    
        update user SET user = #{name} WHERE id = #{id}
    

5、获取接口实现类

  • 在业务层需要与数据库交互时,可通过以下代码来获取DAO实现类
SqlSession sqlSession = Utils.getSqlSession();
userMapper userMapper = sqlSession.getMapper( userMapper.class );
userMapper.deleteUser( 3 );
sqlSession.commit();
sqlSession.close();
// Mybatis CRUD操作
public class MybatisTest {
    @Test
    public void test() {
        
        // 在try的括号中开启sqlSession,无需管理流的关闭
        // 语句块结束之后,能够自动关闭sqlSession
        try ( SqlSession sqlSession = Utils.getSqlSession() ) {
            // sqlSession.getMapper(接口名.class)
            // 在配置文件xml中实现接口,得到实现类
            userMapper userMapper = sqlSession.getMapper( userMapper.class );

            // select
            List< User > userList = userMapper.getUserList();
            for ( User user : userList ) {
                System.out.println( user );
            }

            // insert
            userMapper.insertUser( new User( 3, "杨鑫" ) );

            // update
            userMapper.updateUser( 3, "林耀博" );

            // delete
            userMapper.deleteUser( 3 );

            // select 不需要commit
            // insert、delete、update 事务操作需要commit
            sqlSession.commit();
        }
    }
}

6、CRUD

6.1 select




Map map = new HashMap();

map.put("key1","value1");
map.put("key2","value2");

mapper.getUserList(map);

6.2 insert


    
    insert into user(id, user) values(#{user.id}, #{user.name})

6.3 update


    
    update user set user = #{name} where id = #{id}

6.4 delete


    delete from user where id = #{id}

6.5 模糊查询SQL

select * from user where name like "%"#{name}"%"

select * from user where name like concat('%',#{name},'%')

7、配置优化

7.1 属性优化

  • 通过配置文件properties存储相关信息
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false
username=root
password=
  • 在核心配置文件mybatis-config.xml中添加内容
  • 通过${key}获取配置文件中对应的value值




    
    
    
    

7.2 别名优化

7.2.1 typeAlias

  • 在核心配置文件mybatis-config.xml中添加字段 typeAliases
  • 存在的意义是减少类全限定名的冗余
  • 在底下的所有Mapper均可使用这些别名

    

7.2.2 package

  • 也可以指定一个包名,Mybatis会在包名下面搜索需要的Java Bean

    

7.2.3 注解@Alias (最方便)

  • 也可以通过注解@Alias(" "),在实体类的上方声明
  • 无需通过typeAliases标签配置
@Alias("User")
public class User {
    private int id;
    private String name;
    
    /*
    *	todo
    */
}

8、设置


  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

9、分页

9.1 SQL Limit分页

select * from user limit 0,3; //从第0(1)条记录开始,选取3条 

9.2 RowBounds分页

RowBounds rowBounds = new RowBounds(0,3);

//第一个参数要写全限定名,指向某一个Mapper接口中的某一个方法
List list = sqlSession.selectList("mybatis.userMapper.getUserList", null, rowbounds);

9.3 PageHelper分页插件

  • 文档地址

    https://pagehelper.github.io/docs/howtouse/

9.3.1 使用步骤

  • 导入Maven依赖

    com.github.pagehelper
    pagehelper
    4.2.0

  • 在mybatis-config.xml中添加默认plugin配置(添加在environment上面)

    
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

9.3.2 使用范例

@Test
public void searchUserByParam()
{
    int pageIndex = 2; //获取第2页的数据
    int pageSize = 10; //每页10条数据
    String orderBy = "create_time ASC"; //排序
 
    //分页信息
    //PageHelper.startPage只会在接下来最近的一条查询语句中生效
    //且必须接的是select语句,不能是增删改语句,否则失效
    PageHelper.startPage(pageIndex, pageSize, orderBy);
    
    //查询条件参数类
    UserSearchParam userSearchParam = new UserSearchParam();
    //userSearchParam.setUserName("pan_junbiao的博客"); //查询条件1
    //userSearchParam.setProvince("广东省"); //查询条件2
 
    //执行分页查询
    //userMapper.searchUserList()返回类型为 Page 然后转化为 PageInfo
    PageInfo userInfoPage = new PageInfo(userMapper.searchUserList(userSearchParam));
 
    //打印用户列表
    List userInfoList = userInfoPage.getList();
    userInfoList.stream().forEach(System.out::println);
 
    //打印分页信息
    System.out.println("当前页码:第" + userInfoPage.getPageNum() + "页");
    System.out.println("分页大小:每页" + userInfoPage.getPageSize() + "条");
    System.out.println("数据总数:共" + userInfoPage.getTotal() + "条");
    System.out.println("总页数:共" + userInfoPage.getPages() + "页");
}

10、多对一

public class student {
    int id;
    String name;
    Teacher teacher;
}

10.1 按照查询嵌套处理(子查询)





    
    
    
    
    
    
    
    


10.2 按照结果嵌套处理(联表查询)





    
    
    
        
    


11、一对多

public class Teacher {
    int id;
    String name;
    List students;
}

11.1 按照查询嵌套处理(子查询)



    


11.2 按照结果嵌套处理(联表查询)




    
    
    
    
    
    
        
        
        
    

12、动态SQL

12.1 IF


12.2 choose、when、otherwise(类似switch)


12.3 where

  • where元素只会在至少有一个子元素的条件返回SQL子句的情况下才去插入WHERE"子句。
  • 而且,若语句的开头为AND"或'OR'"where元素也会将它们去除。

12.4 set

  • set元素会动态前置SET关键字,同时也会删掉多余的逗号

    update Author
    
        username=#{username},
        password=#{password},
        email=#{email},
        bio=#{bio}
    
    where id=#{fid}

12.5 trim

属性 描述
prefix 给sql语句拼接的前缀
suffix 给sql语句拼接的后缀
prefixOverrides 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
suffixOverrides 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定

示例:

  

12.6 SQL片段

  • 使用sql标签抽取公共的部分
  • 在需要的地方使用include标签引用即可

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




12.7 foreach

HashMap map = new HashMap();
ArrayList ids = new ArrayList();
ids.add(1);

map.put( "ids",ids ) ;
List blogs = mapper.queryBlogForeach( map );

for (Blog blog : blogs) {
    system.out.print1n(blog);
}
  • collection的对应:
  • map的key为ids,value为id列表
  • id列表变量名为ids,select标签的parameterType为java.util.List

13、缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
  • MyBatis系统中默认定义了两级缓存:一级缓存二级缓存
    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)。
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。

13.1 一级缓存

  • 一级缓存也叫本地缓存:
    • 默认情况开启一级缓存。
    • 与数据库同一次会话期间(SqlSession)查询到的数据会放在本地缓存中。
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

13.2 二级缓存

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

  • 基于namespace级别的缓存,一个名称空间(Mapper接口),对应一个二级缓存。

  • 工作机制:

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

    • 在mybatis-config.xml中开启全局缓存
    
    
        
    
    
    • 在需要使用二级缓存的Mapper中开启
    
    
    

    ? 也可以自定义参数

    
    
    

    小结:

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

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

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

    • 缓存查询顺序:

      • 二级缓存
      • 一级缓存
      • 数据库查询

14、注意事项

14.1 xml文件资源导出失败时

  • 在pom.xml添加以下代码
  • 这样写在java文件夹下的配置文件和Mapper.xml都能导出了

    
        
            src/main/resources
            
                **/*.properties
                **/*.xml
            
            true
        
        
            src/main/java
            
                **/*.properties
                **/*.xml
            
            true
        
    

14.2 resource,路径要用 / 分开 ,不要用 .

14.3 实体类属性名和数据库字段名不一致的问题

  • 方案一:SQL语句中,对应字段起别名 as xxx
  • 方案二:resultMap
数据库:id user
实体类:id name
第二个字段没有对应




    
    
    
    



15、SpringBoot+Mybatis

import org.apache.ibatis.annotations.*;
import springboot.bean.Department;


//Mapper接口通过@Autowired注入
@Mapper   //告诉mybatis这是一个操作数据库的mapper
public interface DepartmentMapper {

    @Select("select * from department where id=#{id}")
    public Department getDeptById(Integer id);

    @Delete("delete from department where id=#{id}")
    public int deleteDeptById(Integer id);

    @Options(useGeneratedKeys = true,keyProperty = "id")   //使用自动生成主键,keyProperty = "id"表示id为封装主键
    @Insert("insert into department(departmentName) values(#{departmentName})")
    public int insertDept(Department department);

    @Update("update department set departmentName=#{departmentName} where id=#{id}")
    public int updateDept(Department department);
}