Mybatis学习笔记

一、快速入门

1、导入依赖

<dependencies>
  <!-- mybatis依赖 -->
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.11</version>
  </dependency>

  <!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! -->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.25</version>
  </dependency>

  <!--junit5测试-->
  <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.3.1</version>
  </dependency>
</dependencies>

2、创建实体类

public class Employee {

    private Integer empId;

    private String empName;

    private Double empSalary;
    
    //getter | setter
}

3、准备一个mapper接口

public interface EmployeeMapper {
    Employee queryById(Integer id);
    void deleteById(Integer id);
}

准备mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.triticale.mapper.EmployeeMapper">
    <!--声明标签写sql语句 crud select insert update delete
        每个标签对应接口的一个方法,方法的一个实现
        注意:mapper接口不能重载,因为mapper.xml无法识别,根据方法名识别
    -->
    <select id="queryById" resultType="com.triticale.pojo.Employee">
        select emp_id empId,emp_name empName, emp_salary empSalary from
        t_emp where emp_id = #{id}
    </select>
    <delete id="deleteById">
        delete from t_emp where emp_id = #{id}
    </delete>
</mapper>

4、准备mybatis的配置文件

<?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">
<configuration>

    <!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
    <environments default="development">
        <!-- environment表示配置Mybatis的一个具体的环境 -->
        <environment id="development">
            <!-- Mybatis的内置的事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 建立数据库连接的具体信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                <property name="username" value="root"/>
                <property name="password" value="yaojinlun"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
        <!-- mapper标签:配置一个具体的Mapper映射文件 -->
        <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
        <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
        <mapper resource="mappers/EmployeeMapper.xml"/>
    </mappers>

</configuration>

5、使用mybatis api进行数据库查找即可

 @Test
    public void test_01() throws IOException {
        //1.读取外部配置文件
        InputStream ips = Resources.getResourceAsStream("mybatis-config.xml");
        //2.创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(ips);
        //3.根据sqlSessionFactory创建sqlSession(每次业务创建一个,用完就释放)
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4.获取接口的代理对象,调用代理对象的方法,就会查找mapper接口的方法
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee employee = mapper.queryById(1);
        System.out.println(employee.toString());
        //5.提交事务(非DQL)释放资源
        sqlSession.close();
    }
二、MyBatis基本使用
2.1 #{} 和 ${}的区别

#{key} : 占位符 + 赋值 相当于 emp_id = ? , ? = 赋值

${key} : 字符串拼接 相当于 "emp_id = " + id

推荐使用#{key},防止 注入攻击 的问题

总结: 如动态的列名 容器名 关键字,使用 ${key}

​ 动态值 使用#{key}

比如 select * from 表 where ${columnName} = #{columnValue}

2.2 数据输入
  • 简单类型(只包含一个值的数据类型)

    传入的单个简单类型的key 随便写, 一般情况下推荐使用参数名

<select id="queryById" resultType="com.triticale.pojo.Employee">
	select emp_id as empId, emp_name as empName, emp_salary as empSalary
	from t_emp where emp_id = #{id}
</select>
<delete id="deleteById">
	delete from t_emp
	where emp_id = #{id}
</delete>
<select id="queryBySalary" resultType="com.triticale.pojo.Employee">
	select emp_id as empId, emp_name as empName, emp_salary as empSalary
	from t_emp where emp_salary = #{salary}
</select>
  • 单个实体对象传入

    key = 对象属性名即可

<insert id="insertEmp">
	insert into t_emp(emp_name, emp_salary) values(#{empName},#{empSalary});
</insert>
  • 传入多个简单值

    方案1:注解指定 @Param注解 指定多个简单参数的key

List<Employee> queryByNameAndSalary(@Param("name") String name, @Param("salary") Double salary)
<select id="queryByNameAndSalary" resultType="com.triticale.pojo.Employee">
	select emp_id as empId, emp_name as empName, emp_salary as empSalary
	from t_emp where emp_name = #{name} and emp_salary = #{salary}
</select>

​ 方案2:mybatis默认机制

​ arg0, arg1 … 形参从左到右依次对应

​ 或者param1,param2 … 形参从左到右依次对应

<select id="queryByNameAndSalary" resultType="com.triticale.pojo.Employee">
	select emp_id as empId, emp_name as empName, emp_salary as empSalary
	from t_emp where emp_name = #{agr0} and emp_salary = #{agr1}
</select>
  • map类型传入
//插入员工数据,传入的是一个map,key为(name=员工的名字,salary=员工的薪水)
    int insertEmpMap(Map data);
<insert id="insertEmpMap">
	insert into t_emp(emp_name ,emp_salary) values(#{name},#{salary});
</insert>
2.3 数据输出

如果是DML语句,返回值均为int

查询语句指定输出类型

resultType语法:

​ 类的全限定符号

​ 别名简称

​ mybatis给我们提供了72种默认的别名

​ 这些都是我们常用的Java数据类型,如果没有提供需要自己定义或者写类的全限定名

<select id="queryNameById" resultType="java.lang.String">
	select emp_name from t_emp where emp_id = #{id}
</select>
<select id="querySalaryById" resultType="double">
	select emp_salary from t_emp where emp_id = #{id}
</select>  

扩展:给自己声明的类定义别名

  • 给类单独定义别名

在config文件中,位置放在的下面

  • 也可以批量设置

这样该包下的所有类都会设置别名,别名是类的首字母小写

  • 批量设置后再单独给类设置别名,使用注解

@Alias(“suibian”)

  • 单个实体类型输出

    返回单个实体类型,要求列名和属性名要一致!

    这样才可以进行实体类的属性映射

    但是可以进行设置,设置支持驼峰式自动映射

    <setting name="mapUnderscoreToCamelCase" value="true"/>
    
  • map类型输出

<select id="selectEmpNameAndMaxSalary" resultType="map">
	select emp_name, emp_salary,(select avg(emp_salary) from t_emp from t_emp where emp_salary = (select max(emp_salary) from t_emp)) from t_emp
</select>
  • 返回List类型
List<String> queryNamesBySalary(Double salary);
List<Employee> queryAll();

返回值是集合的话,resultType不需要指定集合类型,只需要指定范型即可

<select id="queryNamesBySalary" resultType="string">
	select emp_name from t_emp whre emp_salary > #{salary}
</select>
<select id="queryAll" resultType="com.triticale.pojo.Employee">
	select * from t_emp
</select>
2.4 自增长主键回显

在一个主键自增长的表中,如果插入数据并且想拿到该数据对应的主键值,可以在mapper.xml文件中对应的标签中添加三个属性

<insert id="insertEmp" useGeneratedKeys="true" keyColumn="emp_id" keyProperty="empId">
	insert into t_emp(emp_name,emp_salary)
	values(#{empName},#{empSalary});
</insert>

其中,useGeneratedKeys=“true” 我们想要数据库自动增加的主键值

keyColumn=“emp_id” 数据库主键列的值

keyProperty=“empId” 接收主键列值的属性

2.5 非自增长主键回显

在一个非主键自增长的表中,比如主键为UUID,我们也可以将维护主键的工作交给mybatis

<insert id="insertTeacher">
	<selectKey order="BEFORE" resultType="string" keyProperty="tId">
		select replace(uuid(),'-','');
	</selectKey>
	insert into teacher(t_id, t_name) values(#{tId},#{tName});
</insert>

其中,order=“before|after” sql语句是在插入语句之前还是之后执行

​ resultType = 返回值类型

​ keyProperty = 查询结果给哪个属性赋值

2.6 自定义映射关系

在select标签中,我们通过指定resultType属性以及开启驼峰映射可以实现单层的映射关系

但是如果在多表查询中,单层映射关系显然不能满足需求

我们可以通过标签和 标签中的resultMap属性来完成自定义映射

<resultMap id="tMap" type="teacher">
	<id column="t_id" property="tId"/>
    <result column="t_name" property="tName"/>
</resultMap>
<select id="queryTeacher" resultMap="tMap">
	select * from tercher where t_id = #{tId}
</select>

resultMap标签中,id 是主键映射关系

result 是普通列的映射关系

三、MyBatis多表映射
3.1 对一查询实现

在实体类中添加查询元素的对象

public class Order {
    private Integer orderId;
    private String orderName;
    private Integer customerId;
    private Customer customer;
}

使用标签

<resultMap id="orderMap" type="order">
	<id column="order_id" property="orderId"/>
	<result column="order_name" property="orderName"/>
	<result column="customer_id" property="customerId"/>
	<association property="customer" javaType="customer">
		<id column="customer_id" property="customerId"/>
        <result column="customer_name" property="customerName"/> 
    </association>
</resultMap>
<select id="queryOrderById" resultMap="orderMap">
	select * from t_order as tor
    join t_customer as tur
    on tor.customer_id = tur.customer_id
    where tor.order_id = #{id};
</select>

中的property是在当前实体类中用来建立关联关系的属性名

javaType是被关联的实体类类型全类名

在这里插入图片描述

3.2 对多查询实现

在实体类中添加查询元素的集合

public class Customer {
    private Integer customerId;
    private String customerName;
    private List<Order> orderList;
}

使用标签

<resultMap id="customerMap" type="customer">
	<id column="customer_id" property="customerId"/>
	<result column="customer_name" property="customerName"/>
	<collection property="orderList" ofType="order">
		<id column="order_id" property="orderId"/>
        <result column="order_name" property="orderName"/>
        <result column="customer_id" property="customerId"/>
	</collection>
</resultMap>
<select id="queryList" resultMap="customerMap">
    select * from t_order as tor join t_customer tur
    on tor.customer_id = tur.customer_id;
</select>

中的property是在当前实体类中用来建立关联关系的属性名

ofType是被关联的实体类类型全类名

3.3 多表映射优化
setting属性属性含义可选值默认值
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIAL

我们可以将autoMappingBehavior设置为full,进行多表resultMap映射的时候,可以省略符合列和属性命名映射规则(列名=属性名,或者开启驼峰映射也可以自定映射)的result标签!

<resultMap id="teacherMap" type="teacher">
    <id property="tId" column="t_id" />
    <!-- 开启自动映射,并且开启驼峰式支持!可以省略 result!-->
<!--        <result property="tName" column="t_name" />-->
    <collection property="students" ofType="student" >
        <id property="sId" column="s_id" />
<!--            <result property="sName" column="s_name" />-->
    </collection>
</resultMap>
四、MyBatis动态语句
4.1 if和where标签
<select id="query" resultType="employee">
	select * from t_emp
	<where>
		<if test="name != null">
			emp_name = #{name}
        </if>
         <if test="salary != null">
            and emp_salary > #{salary}
         </if>
	</where>
</select>

如果传入属性,就判断相等,如果不传入,不加对应的条件
if 判断传入的参数,最终是否添加语句
test属性,内部做比较运算,最终true将标签内的sql语句进行拼接
false则不拼接
where标签的作用有两个:
1、自动添加where关键字,where内部有任何一个if满足,自动添加where关键字,不满足去掉where
2、自动去掉多余的and 和 or关键字

4.2 set标签
<update id="updateEmployeeDynamic">
    update t_emp
    <!-- set emp_name=#{empName},emp_salary=#{empSalary} -->
    <!-- 使用set标签动态管理set子句,并且动态去掉两端多余的逗号 -->
    <set>
        <if test="empName != null">
            emp_name=#{empName},
        </if>
        <if test="empSalary &lt; 3000">
            emp_salary=#{empSalary},
        </if>
    </set>
    where emp_id=#{empId}
    <!--
         第一种情况:所有条件都满足 SET emp_name=?, emp_salary=?
         第二种情况:部分条件满足 SET emp_salawo ry=?
         第三种情况:所有条件都不满足 update t_emp where emp_id=?
            没有set子句的update语句会导致SQL语法错误
     -->
</update>

set标签可以 1、自动去掉多余的 ,

​ 2、自动添加set关键字

4.3 trim标签

使用trim标签控制条件部分两端是否包含某些字符

  • prefix属性:指定要动态添加的前缀
  • suffix属性:指定要动态添加的后缀
  • prefixOverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
  • suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值
4.4 choose/when/otherwise 标签

在多个分支条件中,仅执行一个。

  • 从上到下依次执行条件判断
  • 遇到的第一个满足条件的分支会被采纳
  • 被采纳分支后面的分支都将不被考虑
  • 如果所有的when分支都不满足,那么就执行otherwise分支
<!-- List<Employee> selectEmployeeByConditionByChoose(Employee employee) -->
<select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
    select emp_id,emp_name,emp_salary from t_emp
    where
    <choose>
        <when test="empName != null">emp_name=#{empName}</when>
        <when test="empSalary &lt; 3000">emp_salary &lt; 3000</when>
        <otherwise>1=1</otherwise>
    </choose>
    
    <!--
     第一种情况:第一个when满足条件 where emp_name=?
     第二种情况:第二个when满足条件 where emp_salary < 3000
     第三种情况:两个when都不满足 where 1=1 执行了otherwise
     -->
</select>
4.5 foreacn 标签

批量操作时使用

	<select id="queryBatch" resultType="employee">
        select * from t_emp 
        where emp_id in
        <foreach collection="ids" open="(" close=")" separator="," item="id">
            #{id}
        </foreach>
    </select>
    <delete id="deleteBatch">
        delete from t_emp where id in
        <foreach collection="ids" open="(" close=")" separator="," item="id">
            #{id}
        </foreach>
    </delete>
    <insert id="insertBatch">
        insert into t_emp(emp_name, emp_salary)
        values
        <foreach collection="list" separator="," item="employee">
            (#{employee.empName},#{employee.empSalary})
        </foreach>
    </insert>
    <update id="updateBatch">
        <foreach collection="list" item="employee">
            update t_emp set emp_name = #{employee.empName}, emp_salary = #{employee.empSalary}
            where emp_id = #{employee.empId};
        </foreach>
    </update>

批量更新时需要注意

上面批量插入的例子本质上是一条SQL语句,而实现批量更新则需要多条SQL语句拼起来,用分号分开。也就是一次性发送多条SQL语句让数据库执行。此时需要在数据库连接信息的URL地址中设置:

atguigu.dev.url=jdbc:mysql:///mybatis-example?allowMultiQueries=true
4.6 sql片段

抽取重读的SQL片段

<!-- 使用sql标签抽取重复出现的SQL片段 -->
<sql id="mySelectSql">
    select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
</sql>

引用已抽取的SQL片段

<!-- 使用include标签引用声明的SQL片段 -->
<include refid="mySelectSql"/>
五、高级扩展
5.1 Mapper 批量映射优化

在配置文件中的标签中添加 标签 属性name指定包

在resources中创建相同结构的文件夹

注意:resources下直接创建多层文件夹使用 / 分割,如果用.分割则是一层文件夹

5.2 分页插件 PageHelper

导入依赖

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.11</version>
</dependency>

在mybatis-config.xml配置分页插件

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="helperDialect" value="mysql"/>
    </plugin>
</plugins>

其中,com.github.pagehelper.PageInterceptor 是 PageHelper 插件的名称,dialect 属性用于指定数据库类型(支持多种数据库)

分页插件的使用

public void test_02(){
	EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
    //调用之前,先设置分页数据(当前是第几页,每页显示多少个)
    PageHelper.startPage(1,2);
    List<Employee> list =  mapper.queryList();
    //将查询数据封装到一个叫PageInfo的分页实体类(一共有多少页,一共有多少页等等)
    PageInfo<Employee> pageInfo = new PageInfo<>(list);
    //从PageInfo中获取分页的数据
    List<Employee> list1 = pageInfo.getList();
    //当前页数
    int pages = pageInfo.getPages();
    //总页数
    long total = pageInfo.getTotal();
    System.out.println(pages);
    System.out.println(total);
}
5.3 逆向工程和MybatisX插件

ORM思维介绍

ORM(Object-Relational Mapping,对象-关系映射)是一种将数据库和面向对象编程语言中的对象之间进行转换的技术。它将对象和关系数据库的概念进行映射,最后我们就可以通过方法调用进行数据库操作

也就是用面向对象的思维进行数据库操作

而逆行工程则是 半自动orm -> 全自动orm迈进

逆向工程MybatisX插件使用

下载插件即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值