mybatis-半自动持久层框架

128 阅读7分钟

mybatis简介

mybatis是一个半自动的持久层框架,具有轻量级,简洁,性能出色的特点。相较于hibernate框架,mybatis的运行效率相对较高,但是由于是半自动的框架,一些单表和多表查询的SQL语句得自己定义。

MyBatis基本使用

1,创建Mapper接口

  • 在mapper层中创建对应的mapper接口
public interface EmployeeMapper {

    //根据id查询员工对象



    //根据员工的id查询员工的姓名
    String queryNameById(Integer id);

    // 根据员工的id查询员工的工资
    Double querysalaryById(Integer id);
    //返回单个实体类型
    Employee queryById(Integer id);

    //查询部门的最高工资和评价工资
    Map<String,Object> selectemployeeNameAndMaxsalary() ;


    //查询工资高于传入值的员工的姓名
    List<String> queryNamesBysalary(Double salary);

    //查询全部的员工信息

    List<Employee> queryAll();

    //员工插入
    int insertEmp(Employee employee);
}
  • 写对应mapper接口的实现(编写配置文件)
<?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="base.mapper.EmployeeMapper">



    <delete id="deleteById" >
        delete from t_emp where emp_id = #{id}
    </delete>


    <!-- 返回值为单个简单类型时
    resultType语法
    类的全限定符号
    别名简称 mybatis 提供了72种默认的别名 ,这些都是我门常用的数据类型如果没有就得自己定义 或者写类的全
    限定符好
    基本数据类型加_
    包装数据类型 小写
    集合容器类型

    自己定义的类是没有别名的

    自己的类如何定义别名
    方案一:使用typealises标签 给类单独设置别名,比较麻烦
    方案二:也可以使用包名加上《package 标签来统一定义别名 别名为类名的首字母小写
    在同一配置的情况下可以在类上加上@Aliases注解来单独设置别名
    -->

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


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

    <select id="queryById" resultType="base.pojo.Employee" >
        select emp_name from t_emp where emp_id = #{id}
    </select>


    <!--

    -->


    <!--
    返回值我为集合类型如何指定resultType

    返回值为集合时
    resultTYpe不需要指定为集合类型
    只需要写为集合的泛型
    mybatis的底层使用的时ibatis ibatis会调用selectone 或者 selectList方法 selectone的底层也调用了
    selectList方法 使用的都是List集合
    -->
    <select id="queryNameBySalary" resultType="string" >
        select emp_name from t_emp where emp_salary > #{salary}
    </select>

    <select id="queryAll" resultType="employee" >
    select * from t_emp
    </select>



    <!--
    主键回显 获取插入数据的主键
    1,自增长逐渐回显

    useGeneratedKeys="true"
    设置为我们想要数据库增长的主键值
    keyColumn="emp_id"
    我们想要获取的主键列
    keyProperty="empId
    返回的主键的值要赋给哪个属性

    2,非自增长类型的主键
    -->
    <insert id="insertEmp" useGeneratedKeys="true" keyColumn="emp_id" keyProperty="empId">
        insert into t_emp (emp_name,emp_salary)
            values(#{empName},#{empSalary})
    </insert>


</mapper>
  • 配置mapper文件到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>
    
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <typeAliases>
        <package name="base.pojo"/>
    </typeAliases>

    <!-- 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="hcx"/>
                <property name="password" value="478016724hcx"/>
            </dataSource>
        </environment>
    </environments>

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

    </mappers>

</configuration>

使用mybatis进行多表映射

对一映射

示例: 根据ID查询订单,以及订单关联的用户的信息!

mapper接口


public interface OrderMapper {
  Order selectOrderWithCustomer(Integer orderId);
}

mapper文件编写如下:

<!-- 创建resultMap实现“对一”关联关系映射 -->
<!-- id属性:通常设置为这个resultMap所服务的那条SQL语句的id加上“ResultMap” -->
<!-- type属性:要设置为这个resultMap所服务的那条SQL语句最终要返回的类型 -->
<resultMap id="selectOrderWithCustomerResultMap" type="order">

  <!-- 先设置Order自身属性和字段的对应关系 -->
  <id column="order_id" property="orderId"/>

  <result column="order_name" property="orderName"/>

  <!-- 使用association标签配置“对一”关联关系 -->
  <!-- property属性:在Order类中对一的一端进行引用时使用的属性名 -->
  <!-- javaType属性:一的一端类的全类名 -->
  <association property="customer" javaType="customer">

    <!-- 配置Customer类的属性和字段名之间的对应关系 -->
    <id column="customer_id" property="customerId"/>
    <result column="customer_name" property="customerName"/>

  </association>

</resultMap>

<!-- Order selectOrderWithCustomer(Integer orderId); -->
<select id="selectOrderWithCustomer" resultMap="selectOrderWithCustomerResultMap">

  SELECT order_id,order_name,c.customer_id,customer_name
  FROM t_order o
  LEFT JOIN t_customer c
  ON o.customer_id=c.customer_id
  WHERE o.order_id=#{orderId}

</select>

对多映射

示例:查询客户和客户关联的订单信息!

mapper接口

public interface CustomerMapper {

  Customer selectCustomerWithOrderList(Integer customerId);

}

mapper编写如下:

<!-- 配置resultMap实现从Customer到OrderList的“对多”关联关系 -->
<resultMap id="selectCustomerWithOrderListResultMap"

  type="customer">

  <!-- 映射Customer本身的属性 -->
  <id column="customer_id" property="customerId"/>

  <result column="customer_name" property="customerName"/>

  <!-- collection标签:映射“对多”的关联关系 -->
  <!-- property属性:在Customer类中,关联“多”的一端的属性名 -->
  <!-- ofType属性:集合属性中元素的类型 -->
  <collection property="orderList" ofType="order">

    <!-- 映射Order的属性 -->
    <id column="order_id" property="orderId"/>

    <result column="order_name" property="orderName"/>

  </collection>

</resultMap>

<!-- Customer selectCustomerWithOrderList(Integer customerId); -->
<select id="selectCustomerWithOrderList" resultMap="selectCustomerWithOrderListResultMap">
  SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
  FROM t_customer c
  LEFT JOIN t_order o
  ON c.customer_id=o.customer_id
  WHERE c.customer_id=#{customerId}
</select>

mybatis动态sql语句

if和where标签

if标签:当条件判断为真时,将sql语句片段与SQL语句进行拼接 where标签:自动去掉“标签体内前面多余的and/or

<!-- List<Employee> selectEmployeeByCondition(Employee employee); -->
<select id="selectEmployeeByCondition" resultType="employee">
    select emp_id,emp_name,emp_salary from t_emp
    <!-- where标签会自动去掉“标签体内前面多余的and/or” -->
    <where>
        <!-- 使用if标签,让我们可以有选择的加入SQL语句的片段。这个SQL语句片段是否要加入整个SQL语句,就看if标签判断的结果是否为true -->
        <!-- 在if标签的test属性中,可以访问实体类的属性,不可以访问数据库表的字段 -->
        <if test="empName != null">
            <!-- 在if标签内部,需要访问接口的参数时还是正常写#{} -->
            or emp_name=#{empName}
        </if>
        <if test="empSalary &gt; 2000">
            or emp_salary>#{empSalary}
        </if>
        <!--
         第一种情况:所有条件都满足 WHERE emp_name=? or emp_salary>?
         第二种情况:部分条件满足 WHERE emp_salary>?
         第三种情况:所有条件都不满足 没有where子句
         -->
    </where>
</select>

set标签

<!-- void updateEmployeeDynamic(Employee employee) -->
<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_salary=?
         第三种情况:所有条件都不满足 update t_emp where emp_id=?
            没有set子句的update语句会导致SQL语法错误
     -->
</update>

choose/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>

foreach标签

使用示例

<!--
    collection属性:要遍历的集合
    item属性:遍历集合的过程中能得到每一个具体对象,在item属性中设置一个名字,将来通过这个名字引用遍历出来的对象
    separator属性:指定当foreach标签的标签体重复拼接字符串时,各个标签体字符串之间的分隔符
    open属性:指定整个循环把字符串拼好后,字符串整体的前面要添加的字符串
    close属性:指定整个循环把字符串拼好后,字符串整体的后面要添加的字符串
    index属性:这里起一个名字,便于后面引用
        遍历List集合,这里能够得到List集合的索引值
        遍历Map集合,这里能够得到Map集合的key
 -->
<foreach collection="empList" item="emp" separator="," open="values" index="myIndex">
    <!-- 在foreach标签内部如果需要引用遍历得到的具体的一个对象,需要使用item属性声明的名称 -->
    (#{emp.empName},#{myIndex},#{emp.empSalary},#{emp.empGender})
</foreach>

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"/>