Mybatis 框架使用指南(进阶)2

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Mybatis 框架使用指南(进阶)2

嵌套查询(了解)


Mybatis嵌套查询 介绍:将多表查询的复杂sql语句拆分多个单表查询,再由mybatis框架进行嵌套组合


  • 优点:减少sql复杂性
  • 缺点:需要编写多次sql和多个配置,代码麻烦。故一般不推荐使用

简单示例:

* 需求:查询一个订单,与此同时查询出该订单所属的用户  1v1
# 关联查询
select * from orders o left join user u on o.uid=u.id where o.id=1;
# 嵌套查询 将一条sql语句能完成的事情拆分成多条单表查询去完成
#1 查询订单号为1的订单
#2 在根据查询的订单的uid去查用户表
#3 mybatis进行组装(映射文件中组装)因最终要返回的是订单 所以去订单映射文件中组装



一对一(多对一)

需求:查询一个订单,与此同时查询出该订单所属的用户

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">
<mapper namespace="cn.test.mapper.OrdersMapper">
    <resultMap id="ordersResultMap" type="orders">
        <id column="id" property="id"></id>
        <result column="ordertime" property="ordertime"></result>
        <result column="address" property="address"></result>
        <!--mybatis框架嵌套查询(一对一映射)
                association标签
                    property:要封装的对象属性名
                    select:数据来源的方法名
                    column:方法需要的参数(uid)
        -->
        <association property="user" select="cn.test.mapper.UserMapper.findUserById" 
                     column="uid">
        </association>
    </resultMap>
    <!-- 查询当前订单 -->
    <select id="findOrderById" parameterType="int" resultMap="ordersResultMap">
        select * from orders where id=#{id}
    </select>
</mapper>
<?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">
<mapper namespace="cn.test.mapper.UserMapper">
    <!-- 查询当前用户 -->
    <select id="findUserByUId" parameterType="int" resultType="user">
        select * from user where id=#{id}
    </select>
</mapper>



一对多

需求:查询一个用户,与此同时查询出该用户具有的订单

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">
<mapper namespace="cn.test.mapper.UserMapper">
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 嵌套查询(一对多的映射)
                collection标签
                    property;要封装的对象集合属性
                    ofType:泛型类型
            select:数据的来源方法  
            column:方法需要的参数数据(用户的id) 
        -->
        <collection property="orders" ofType="Orders" select="cn.test.mapper.OrdersMapper.findBylist" 
                    column="id">
        </collection>
    <!-- 查询当前用户 -->
    </resultMap>
    <select id="findUserById" parameterType="int" resultMap="userResultMap">
        select * from user where id=#{id}
    </select>
</mapper>
<?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">
<mapper namespace="cn.test.mapper.OrdersMapper">
    <!--查询多个订单-->
    <select id="findBylist" parameterType="int" resultType="Orders">
        select * from orders where uid=#{id}
    </select>
</mapper>



多对多(由二个一对多组成)

需求:查询用户同时查询出该用户的所有角色

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">
<mapper namespace="cn.test.mapper.UserMapper">
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 嵌套查询(一对多的映射)
                collection标签
                    property;要封装的对象集合属性
                    ofType:泛型类型
                    select:数据的来源方法  
           column:方法需要的参数数据(用户的id)
        -->
        <collection property="roleList" ofType="role" select="cn.test.mapper.RoleMapper.findRoles" 
                    column="id">
        </collection>
    </resultMap>
    <!--查询当前用户-->
    <select id="findUserById" parameterType="int" resultMap="userResultMap">
        select * from user where id=#{id}
    </select>
</mapper>
<?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">
<mapper namespace="cn.test.mapper.RoleMapper">
    <resultMap id="RoleResultMap" type="role">
        <id column="id" property="id"></id>
        <result column="role_name" property="roleName"></result>
        <result column="role_desc" property="roleDesc"></result>
    </resultMap>
    <!--查询当前用户的角色-->
    <select id="findRoles" resultMap="RoleResultMap" parameterType="int">
        SELECT * FROM user_role ur INNER JOIN role r ON ur.rid=r.id WHERE ur.uid=#{id}
    </select>
</mapper>



调用存储过程

参考:MyBatis 调用存储过程(详解)


在mapper文件中可以使用statementType标记使用什么的对象操作SQL语句。


statementType:标记操作SQL的对象


取值说明:

   STATEMENT:直接操作sql,不进行预编译,获取数据。$—Statement

   PREPARED:预处理,参数,进行预编译,获取数据。#—PreparedStatement。默认

   CALLABLE:执行存储过程。CallableStatement


示例:

  1. 创建insert_user存储过程(MySql)
CREATE PROCEDURE insert_user(OUT u_id INTEGER,IN u_name VARCHAR(20),IN u_sex VARCHAR(20),IN u_age INTEGER)
BEGIN
INSERT INTO t_user (name,sex,age) VALUES (u_name,u_sex,u_age);
SET u_id=LAST_INSERT_ID();
END


在UserMapper.xml中调用insert_user存储过程

<!-- 添加用户 -->
<insert id="addUser" parameterType="com.po.User" statementType="CALLABLE">
    {call insert_user(#{id,mode=OUT,jdbcType=INTEGER},#{name,mode=IN},#{sex,mode=IN},#{age,mode=IN})}
</insert>


2.创建deleteUser存储过程(MySql)

CREATE PROCEDURE deleteUser(IN u_id INTEGER)
BEGIN
   DELETE FROM t_user WHERE id=u_id;
END

在UserMapper.xml中调用deleteUser存储过程

<!-- 删除用户 -->
<delete id="deleteUser" parameterType="Integer" statementType="CALLABLE">
    {call deleteUser(#{id,mode=IN})}
</delete>



3.创建updateUser存储过程(MySql)

CREATE PROCEDURE updateUser(IN u_id INTEGER,IN u_name VARCHAR(20),IN u_sex VARCHAR(20),IN u_age INTEGER)
BEGIN
    UPDATE t_user SET name=u_name,sex=u_sex,age=u_age WHERE id=u_id;
END


在UserMapper.xml中调用updateUser存储过程

<!-- 更新用户 -->
<update id="updateUser" parameterType="user" statementType="CALLABLE">
    {call updateUser(#{id,mode=IN},#{name,mode=IN},#{sex,mode=IN},#{age,mode=IN})}
</update>


4.创建getUserById存储过程(MySql)

CREATE PROCEDURE getUserById(IN u_id INTEGER)
BEGIN
    SELECT id,name,sex,age FROM t_user WHERE id=u_id;
END


在UserMapper.xml中调用getUserById存储过程

<!-- 根据id查询用户 -->
<select id="getUserById" parameterType="Integer" resultType="user" statementType="CALLABLE">
    {call getUserById(#{id,mode=IN})}
</select>




拓展了解

Mybatis 核心文件概述



1)environments标签

数据库环境配置



 1.  其中,事务管理器(transactionManager)类型有两种:


   JDBC:

   这个配置就是直接使用了JDBC 的提交和回滚设置,由mybatis自己手动控制事务


   MANAGED:

   这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。

   例如:mybatis与spring整合后,事务交给spring容器管理。


2.    其中,数据源(dataSource)常用类型有二种:


   UNPOOLED:

   这个数据源的实现只是每次被请求时打开和关闭连接。


   POOLED:

   这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。使用的是mybatis自带的


2)properties标签

第三方属性配置

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件

   <properties resource="jdbc.properties"></properties> 
   <environments default="mysql">
        <!--mysql数据库环境-->
        <environment id="mysql">
            <!-- 使用JDBC类型事务管理器 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 数据源(连接池)配置  POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>



3)typeAliases标签

实体类型别名配置

  <typeAliases>
        <!--指定一个实体类和对应的别名-->
        <!--<typeAlias type="com.test.domain.User" alias="user"></typeAlias>-->
        <!--指定当前包下所有的实体设置别名  默认: 别名(类名) -->
        <package name="com.test.domain"></package>
    </typeAliases>

394b79c9b16a400da863592cbe7fcec9.png


4)mappers标签

映射关系配置(加载映射配置文件)

<!-- 加载指定的src目录下的映射文件 -->
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>



核心配置文件标签顺序




Mybatis 的 API 概述


1)Resources

专门用于加载mybatis核心配置文件,返回的 io流

InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");



2)SqlSessionFactoryBuilder

专门用于生产SqlSessionFactory工厂对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);



3)SqlSessionFactory

一个项目只有一个工厂对象,生产sqlSession对象

// 需要手动提交事务,DML语句才会持久化到数据库中
SqlSession openSession(); // 【推荐】
// 设置是否开启自动提交,如果设置为true,开启自动提交事务
SqlSession openSession(boolean autoCommit);
  参数说明
    true:每一条DML类型语句都会自动提交事务
    false(默认值):需要手动提交事务



4)SqlSession

是mybatis核心对象,可以对数据库进行CRUD基本操作

//  方法
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement, Object parameter);
int insert(String statement, Object parameter);
int update(String statement, Object parameter);
int delete(String statement, Object parameter);
// 事务
void commit();
void rollback();




MyBatis 延迟加载(懒加载)


Mybatis的延迟加载是针对嵌套查询而言的,是指在进行查询的时候先只查询最外层的SQL,对于内层SQL将在需要使用的时候才查询出来。


使用延迟加载的场景:一对多、多对多

不推荐使用延迟加载的场景:一对一(使用 立即加载)

特别注意:延迟加载是基于 嵌套查询 组合使用

1)局部延迟加载

* 需要手动在每一个select相关标签中单独配置
  <association>、<collection>
    fetchType="lazy"  懒加载
    fetchType="eager" 立即加载


2)全局延迟加载

lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载,特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。默认值为false。

  <!-- 在核心配置文件SqlMapConfig.xml,设置全局参数 -->
    <settings>
        <!--开启懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>


若是pringboot集成,在yaml配置文件中配置开启延迟加载。

mybatis:
  configuration:
    lazy-loading-enabled: true    #开启延时加载开关


注意:如果全局配置了延迟加载,那么一对一也会起作用

可以为一对一设置局部的立即加载,因为局部优先级高于全局延迟加载

<association property="user" javaType="User" column="uid" select="com.itheima.mapper.UserMapper.findById" 
             fetchType="eager"> 
</association>


3)指定触发延迟加载的方法配置

lazyLoadTriggerMethods 默认情况下仅仅支持自动将 equals,clone,hashCode,toString 这几个方法定义为延迟加载的加载触发方法。

* 在SqlMapConfig.xml核心配置文件,设置全局参数
  <settings>
    <!-- 如果将 Person 的 doLazyLoadingNow()方法加入这个列表中,
       则调用 doLazyLoadingNow()方法将会导致 Person 上的所有延迟加载属性的关联对象被执行加载。 -->
    <setting name="lazyLoadTriggerMethods" value="doLazyLoadingNow,equals,clone,hashCode,toString"/>
  </settings>


若是springboot集成,在yaml配置文件中配置

mybatis:
  configuration:
    lazy-loading-enabled: true    # 开启延时加载开关
    aggressive-lazy-loading: false  # 将积极加载改为消极加载(即按需加载),默认值就是false
    # 指定触发延迟加载的方法
    lazy-load-trigger-methods: "doLazyLoadingNow,equals,clone,hashCode,toString"
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2天前
|
SQL Java 数据库连接
MyBatis 框架入门理论与实践
MyBatis 框架入门理论与实践
31 6
|
2天前
|
SQL 缓存 Java
持久层框架MyBatis
MyBatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的操作。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
27 1
|
2天前
|
SQL 缓存 Java
【框架】MyBatis 框架重点解析
【框架】MyBatis 框架重点解析
7 0
|
2天前
|
SQL Java 数据库连接
【JavaEE】懒人的福音-MyBatis框架—复杂的操作-动态SQL(下)
【JavaEE】懒人的福音-MyBatis框架—复杂的操作-动态
5 0
|
2天前
|
SQL Java 数据库连接
【JavaEE】懒人的福音-MyBatis框架—复杂的操作-动态SQL(上)
【JavaEE】懒人的福音-MyBatis框架—复杂的操作-动态SQL
4 0
|
2天前
|
SQL Java 数据库连接
【JavaEE】懒人的福音-MyBatis框架—[单表]增删改查等常规操作(下)
【JavaEE】懒人的福音-MyBatis框架—[单表]增删改查等常规操作
6 0
|
2天前
|
SQL 前端开发 Java
【JavaEE】懒人的福音-MyBatis框架—[单表]增删改查等常规操作(上)
【JavaEE】懒人的福音-MyBatis框架—[单表]增删改查等常规操作
8 0
|
2天前
|
Java 数据库连接 数据库
【JavaEE】懒人的福音-MyBatis框架—介绍、搭建环境以及初步感受
【JavaEE】懒人的福音-MyBatis框架—介绍、搭建环境以及初步感受
6 0
|
2天前
|
XML Java 数据库连接
Java一分钟之MyBatis:持久层框架基础
【5月更文挑战第15天】MyBatis是Java的轻量级持久层框架,它分离SQL和Java代码,提供灵活的数据库操作。常见问题包括:XML配置文件未加载、忘记关闭SqlSession、接口方法与XML映射不一致、占位符使用错误、未配置ResultMap和事务管理不当。解决这些问题的关键在于正确配置映射文件、管理SqlSession、避免SQL注入、定义ResultMap以及确保事务边界。遵循最佳实践可优化MyBatis使用体验。
12 2
Java一分钟之MyBatis:持久层框架基础
|
2天前
|
SQL 缓存 Java