返回

MyBatis:热门的持久层框架

事先声明

本人根据 bilibili 视频博主楠哥教你学Java所发布的视频【极简入门】4小时学会MyBatis的课程内容进行学习及整理

本视频应该是我在B站找到的单独讲解MyBatis的所有视频中最精简,最快速的学习视频,非常适合于我一样,马上毕业了的大四小白🐶

在这里进行强烈推荐

本人为了便于学习,将其挂在了我的个人网站上,如对UP主的权益有所侵犯,请通过admin@xon.ink与我联系

MyBatis简介

MyBatis是 Apache 的一个开源项目 iBatis ,2010年这个项目由 Apache Software Foundation迁移到了 Google Code,并改名为 MyBatis,2013年11月迁移到了 Github

现在的MyBatis中依然有很多依然用iBatis命名的包名,没有改过来

MyBatis 是一个是一个实现了数据持久化的开源框架,简单理解就是对 JDBC 进行了封装

ORMapping:对象关系映射

ORMapping:对象关系映射 (Object Relationship Mapping)

对象指面向对象(Java)

关系指关系型数据库(MySQL或关系型数据库)

Java到MySQL的映射,开发者可以以面向对象的思想来管理数据库

MyBatis的优点

  • 与JDBC相比,减少了50%以上的代码量
  • MyBatis是最简单的持久化框架,小巧并且简单易学
  • MyBatis相当灵活,不会对应用程序或数据库现有的设计强加任何影响,SQL写在了XML中,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用
  • 提供XML标签,支持动态编写SQL语句
  • 提供映射标签,支持对象与数据库的ORM字段关系映射

MyBatis的缺点

  • SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此。对开发人员编写SQL语句的功底有一定的要求
  • SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库

MyBatis的核心接口和类

graph TD
SqlSessionFactoryBuilder -.build.-> SqlSessionFactory -.openSession.->SqlSession

MyBatis的开发方式

  • 使用原生接口
  • Mapper代理实现自定义接口

搭建MyBatis环境(IDEA)

创建简单的数据模型

因为是ORMapping

我们需要分别创建关系类型 (Relationship) ,以及对象 (Object) 类型的创建

并且两者的数据应该互相匹配在能在后期完成映射

创建Maven pom.xml

<configuration>
  <dependencies>
    <!-- 导入Mybatis依赖 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
    </dependency>
    <!-- 导入Mysql依赖(因为Mybatis基于JDBC) -->
    <dependencies>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
      </dependency>
    </dependencies>
    <!-- 插入自定义规范依赖 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.6</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <!-- Maven中无法读取main目录下的xml文件
			 所以在pom.xml文件中加入对应的<build>标签及内容 -->
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
        </includes>
      </resource>
    </resources>
  </build>
</configuration>

创建数据表

create table t_account(
  id int primary key auto_increment,
  username varchar(11),
  password varchar(11),
  age int
)

创建对象

  1. 新建数据表对应的实体类Account
import lombok.Data;

@Data
public class Account {
    private long id;
    private String username;
    private String password;
    private int age;
}

创建MyBatis全局配置文件config.xml

文件名可以自定义

创建配置文件config.xml ,在项目src/main/resources目录中(Maven中)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--XML头文件-->

<configuration>
	<!-- 配置MyBatis运行环境 -->
  <environments default="development">
  	<environment id="development">
      <!-- 配置JDBC的事务管理 -->
    	<transactionManager type="JDBC"></transactionManager>
      
      <!-- POOLED配置JDBC数据源链接池 -->
      <dataSource type="POOLED">
        <!-- 配置JDBC的四个步骤 -->
        <!-- 1.配置JDBC驱动 -->
      	<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
        <!-- 2.配置JDBC链接路径
						   当然可以指定字符集,在链接末尾加入
						   ?useUnicode=true&amp;characterEncoding=UTF-8 -->
        <property name="url" value="jdbc:mysql://localhost:3306/databaseName"></property>
        <!-- 3.配置数据库的用户名 -->
        <property name="username" value="root"></property>
        <!-- 4.配置数据库的密码 -->
        <property name="password" value="1234"></property>
      </dataSource>
    </environment>
    
    <!-- 为了适应多个数据源的链接
				 environment标签必须包含在environments标签中
    <environment id="development1">
    	<transactionManager type=""></transactionManager>
      <dataSource type=""></dataSource>
    </environment>
		-->
  </environments>
</configuration>
graph TD
subgraph config.xml
	mysql(MySQL)
	subgraph environments
  	transactionManager -.配置JDBC事务.-> JDBC
  	dataSource -.配置JDBC数据池.-> JDBC
  	JDBC --> mysql
  end
  subgraph mappers
  	mapper -.注册mapper文件.-> mapper.xml
  end
end

使用原生接口

Mybatis框架需要开发者自定义SQL语句,写在Mapper.xml文件中,在实际开发中,会为每个实体类创建对应的Mapper.xml,定义管理该对象数据的SQL

新建对应类的Mapper

新建放置mapper文件的包,里面统一放置Mapper的xml文件

在包中新建一个xml文件,命名为XXXXMapper.xml,名字应与类对应

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- XML头文件 -->

<mapper namespace="com.xon.mapper.AccountMapper">
  <!-- Mybatis的每种操作在Mapper文件中都有对应的标签-->
  
  <!-- 表添加动作的标签 -->
	<insert id=""></insert>
  <!-- 表修改动作的标签 -->
  <update id=""></update>
  <!-- 表删除动作的标签 -->
  <delete id=""></delete>
  <!-- 表查询动作的标签 -->
  <select id=""></select>
</mapper>
  • namespace 通常设置为文件所在包+文件名的形式

  • 具体例子

    <mapper namespace="com.xon.mapper.AccountMapper">
    	<insert id="save" parameterType="com.xon.entity.Account">
          insert into t_account(username,password,age)
        values(#{username},#{password},#{age})
      </insert>
    </mapper>
    
    • id 是实际调用Mybatis方式时需要调用的参数
    • parameterType 是调用对应方法时参数的数据类型

在全局配置中注册Mapper

config.xml文件中添加相应标签注册AccountMapper.xml

<configuration>
  <!-- 在底部继续添加 -->
	<mappers>
  	<mapper resource="com/xon/mapper/AccountMapper.xml"></mapper>
  </mappers>
</configuration>

因为注册文件的路径需要添加.xml文件的后缀。如果用符号.对文件目录进行分割的话,就无法区分后缀还是子目录

所以目录之间用 / 代替

调用原生接口执行添加操作

新建放置repository文件的包(未完成)

public class DemoByNative {
  public static void main(String[] args) {
    //加载MyBatis配置文件
    InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //指定Mapper的位置 路径为 namespace.id
    String statement = "com.xon.mapper.AccoutMapper.save";
    //创建数据对象
    Account account = new Account(1L,"张三","123123",22);
    //执行添加操作(Mapper路径,添加的数据)
    sqlSession.insert(statement,account);
    //提交事物
		sqlSession.commit();
    //关闭
    sqlSession.close();
  }
}

Mapper代理实现自定义接口

  • 自定义接口,定义相关业务方法
  • 编写与方法相对应的Mapper.xml
  • 在接口中声明对象 –> 在mapper.xml中添加方法8

自定义接口

创建包repository

创建接口 AccountRepository

public interface AccountRepository {
  // 实现增加的方法
  public int save(Account account);
  // 实现修改的方法
  public int update(Account account);
  // 实现删除的方法,通过查找id的方式
  public int deleteById(long id);
  // 实现查询的方法
  public List<Account> findAll();
  // 实现查询的方法,通过查找id的方式
  public Account findById(long id);
}

创建接口对应的Mapper.xml

定义接口方法对应的SQL语句

<statement> 标签可以根据SQL执行的业务选择 insertdeleteupdateselect

Mybatis 框架会根据规则自动创建接口实现类的代理对象

在repository中创建AccountRepository.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- XML头文件 -->

<mapper namespace="com.xon.repository.AccountRepository">
    <insert id="save" parameterType="com.xon.entity.Account">
        insert into t_account(username,password,age) values(#{username},#{password},#{age})
    </insert> 
    <update id="update" parameterType="com.xon.entity.Account">
        update t_account set username = #{username},password = #{password},age = #{age} where id = #{id}
    </update>
    <delete id="deleteById" parameterType="long">
        delete from t_account where id = #{id}
    </delete>
    <select id="findAll" resultType="com.xon.entity.Account">
        select * from t_account
    </select>
    <select id="findById" parameterType="long" resultType="com.xon.entity.Account">
        select * from t_account where id = #{id}
    </select>
</mapper>

规则

  • Mapper.xml 中 namespace.xml 为接口的全类名
  • Mapper.xml 中 statement 的 id 为接口中对应的方法名
  • Mapper.xml 中 statement 的 parameterType 和接口中对应的方法参数一致
  • Mapper.xml 中 statement 的 resultType 和接口中对应方法的返回值类型一致

小知识

insertdelete 返回执行语句的行数,肯定为int所以不用指定返回类型

delete中的parameterType也可以写全"java.lang.long"

查询语句不应该写<List> 应该写Account的范型

在全局配置文件中注册Mapper

<configuration>
  <!-- 在底部继续添加 -->
	<mappers resource="com/xon/repository/AccountRepository.xml"></mappers>
</configuration>

调用代理接口执行操作

public class DemoByProxy {
  public static void main(String[] args) {
    //加载MyBatis配置文件
    InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取实现接口的代理对象
    AccountRepository accountRepository = sqlSession.getMapper(AccountRepository.class);
    //添加对象
    Account account = new Account(2L,"李四","123123",23)
    accountRepository.save(account);
    //增删改操作一定要提交事物
    sqlSession.commit();
    sql.close();
    
    //查找所有
    List<Account> list accountRespository = findAll();
    for(Account account:list){
      System.out.println(account);
    	sqlSession.close();
    }
    
    //通过Id查询
    Account account = accountRespository.findById(3L);
    System.out.println(account);
    sql.close();
    
    //修改对象
    Account account = accountRespository.findById(3L);
    account.setUsername("小明");
    account.setPassword("000");
    account.setAge(18);
    int result = accountRespository.update(account);
    System.out.println(result);
    sqlSession.commit();
    sqlSession.close();
    
    //通过Id删除对象
    int result = accountRespository.deleteById(3L);
    System.out.println(result);
    sqlSession.commit();
    sqlSession.close();
  }
}

Mapper.xml

statement 标签

  • select : 查询
  • update : 修改
  • delete : 删除
  • insert : 添加

parameterType 参数数据类型

  • 基本数据类型通过Id查询 Account

    <select id="findById" parameterType="long" resultType="com.xon.entity.Account">
    	select * from t_account where id = #{id}
    </select>
    
  • String类型,通过 name 查询 Account

    <select id="findByName" parameterType="java.lang.String"resultType="com.southwind.entity.Account">
      select * from t_account where username = #{username}
    </select>
    

    想实现name查找,在别忘了在接口中定义方法

  • 包装类,通过id查询Account

    <select id="findById2" parameterType="java.lang.Long" resultType="com.southwind.entity.Account">
      select * from t_account where id = #{id}
    </select>
    

    其实和id查询的区别就是把long 换成了对象

    好处就是可以返回null值了

  • 多个参数,通过nameage查询 Account

    <select id="findByNameAndAge" resultType="com.southwind.entity.Account">
      select * from t_account where username = #{param1} and age = #{param2}
    </select>
    

    因为多个参数无法指定一种类型,所以不用写参数类型

    sql中通过下标的方式来指定参数,下面是指定下标的两种方式

    • param:下标从 1 开始,{param1}{param2}
    • arg : 下标从 0 开始,{arg0}{arg1}
  • JavaBean

    <update id="update" parameterType="com.xon.entity.Account">
        update t_account set username = #{username},password = #{password},age = #{age} where id = #{id}
    </update>
    

resultType 结果类型

  • 基本数据类型,统计Account总数

    <select id="count" resultType="int">
    	select count(id) from t_account
    </select>
    
  • 包装类,统计 Account 总数

    <select id="count" resultType="java.lang.Integer">
    	select count(id) from t_account
    </select>
    
  • String 类型,通过 id 查询 Account 的 name

    <select id="findNameById" resultType="java.lang.String">
    	select username from t_account where id = #{id}
    </select>
    
  • Java Bean

    <select id="findById" parameterType="long" resultType="com.xon.entity.Account">
        select * from t_account where id = #{id}
    </select>
    

级联查询

一对多关系

comments powered by Disqus