Mybatis复杂查询

  • 了解mybatis连接池技术

  • 掌握mybatis事务操作

  • 掌握mybatis动态sql

  • 掌握mybatis多表关联查询

mybatis连接池技术【了解】

总结jdbc开发问题中,我们说mybatis内部提供了连接池。在sqlMapConfig.xml中配置数据源:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MsYs814n-1582184761985)(media/2e286633290cc6b477acb8cabebfa374.png)]

POOLED即是mybatis内部提供的连接池。

连接池分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jZNyA7PA-1582184761985)(media/47b415bd0e51710d961529f12db12b22.png)]

mybatis中将连接池(数据源)分为三类:

  • jndi:使用jndi实现数据源

  • pooled:使用连接池的数据源

  • unpooled:不使用连接池的数据源

三类数据源中我们通常使用的是pooled。mybatis框架提供了实现javax.sql.DataSource接口的实现类:PooledDataSource、UnpooledDataSource来表示pooled和unpooled类型的数据源。具体结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PvxNsa1g-1582184761986)(media/54525d267918d80bd97a3d7c219de9ce.png)]

在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术)。

mybatis动态sql

动态sql指的是运行时sql,根据传入的参数情况,决定最终执行的sql语句。在动态sql中,主要关心以下标签的使用:

  • if

  • where

  • set

  • sql

  • include

  • foreach

动态sql案例

需求

根据用户名称和性别查询用户数据。

声明mapper接口方法

package com.dao;

import com.po.QueryPo;
import com.po.User;

import java.util.ArrayList;
import java.util.List;

public interface UserDao {
    //使用if标签
    List<User> findByUser1(User user);

    //使用where标签
    List<User> findByUser2(User user);

    //使用foreach标签1
    List<User> findByIds(QueryPo queryPo);

    //使用foreach标签2
    int deleteUsers(ArrayList<Integer> ids);

    //使用set标签
    int update(User user);

}

if标签(不建议单独使用)

作用:判断传入的参数情况,拼装sql语句片段

单独使用if标签时,因为sql语句约束条件不能以and开头,所以我们使用了where 1=1的多余语句。也因此,不建议单独使用if标签。

<select id="findByUser1" parameterType="com.po.User" resultType="com.po.User">
    select * from  user where 1=1
    <!--if:判断用户名称不为null,且不为空字符串,则作为查询条件-->
    <if test="username != '' and username != null">
        and username like #{username}
    </if>
    <!--if:判断用户性别不为null,且不为空字符串,则作为查询条件-->
    <if test="sex != '' and sex !=null">
        and sex = #{sex}
    </if>
</select>

where标签

作用:

  1. 相当于sql语句中的where关键字

  2. 根据传入的参数情况,智能的去掉多余的and、or和where关键字

<select id="findByUser2" parameterType="com.po.User" resultType="com.po.User">
    select * from  user
    <where>
        <if test="username != '' and username != null">
            username like #{username}
        </if>
        <if test="sex != '' and sex != null">
            sex like #{sex}
        </if>
    </where>
</select>

set标签

作用:

  1. 相当于sql语句中的set关键字

  2. 根据传入的参数情况,智能的去掉最后一个多余的逗号

  <!-- 动态修改用户数据 -->
    <update id="update" parameterType="com.po.User">
        update user
        <set>
            <if test="username != null and username !=''">
                username=#{username},
            </if>
            <if test="sex != null and sex !=''">
                sex=#{sex},
            </if>
        </set>
        <where>
            id=#{id}
        </where>
    </update>

sql、include标签

作用:

  1. 提取公共的sql语句片段

  2. include标签用于引用sql标签

<!--sql:提取公共的sql语句片段,说明:
    id:唯一标识名称,通过id引用该sql片段
-->
<sql id="selectSql">
    select * from  user
</sql>

<select id="findByUser2" parameterType="com.po.User" resultType="com.po.User">
    <!--使用提取出来的sql语句-->
    <include refid="selectSql"/>
    <where>
        <if test="username != '' and username != null">
            username like #{username}
        </if>
        <if test="sex !=‘’ and sex != null">
            sex like #{sex}
        </if>
    </where>
</select>

foreach标签

作用:循环处理参数集合(list、数组)。

使用方法一:

查找多个id下对应的User

声明mapper接口方法

package com.po;

import java.util.ArrayList;

public class QueryPo {

    private ArrayList<Integer> ids;

    public QueryPo() {
    }

    public QueryPo(ArrayList<Integer> ids) {
        this.ids = ids;
    }

    public ArrayList<Integer> getIds() {
        return ids;
    }

    public void setIds(ArrayList<Integer> ids) {
        this.ids = ids;
    }

    @Override
    public String toString() {
        return "QueryPo{" +
                "ids=" + ids +
                '}';
    }
}

配置mapper映射文件

<!--查找多个id下对应的User-->
<select id="findByIds" parameterType="com.po.QueryPo" resultType="com.po.User">
    <!-- select * from  user-->
    <include refid="selectSql"/>
    <where>
        <if test="ids != null and ids.size() > 0 ">
            <!-- foreach:循环处理参数集合
                        collection:参数集合,来自parameterType的属性名
                        item:当前遍历的对象
                        separator:指定分割符
                     -->
            <foreach collection="ids" open=" id in (" close=" )" separator="," item="id">
                #{id}
            </foreach>
        </if>
    </where>
</select>

使用方法2

实现批量删除用户

声明mapper接口方法

//使用foreach标签2
int deleteUsers(ArrayList<Integer> ids);

配置mapper映射文件

<!-- 批量删除用户,说明:
parameterType:当参数传递的是list和数组,都建议写成list
-->
<delete id="deleteUsers" parameterType="list">
    delete from `user`
    where
    <!--foreach:循环处理参数集合,说明:
            collection:参数集合,来自parameterType
            open:拼装的sql语句片段的开始部分
            close:拼装的sql语句片段的结束部分
            item:当前遍历的元素
         -->
    <foreach collection="list" open="id in(" close=")" item="id" separator=",">
        #{id}
    </foreach>
</delete>

mybatis多表关联查询

关联关系分类

一对一关联关系

举一个例子:人和身份证的关系。一个人只能有一张身份证,一张身份证只能属于一个人。【双向】一对一关联关系。

一对多关联关系

举一个例子:人和账户的关系。一个人可以有多个账户,从人到账户是【一对多】关联关系。一个账户只能属于一个人,从账户到人是【一对一】的关联关系。

多对多关联关系–双向一对多就是多对多

举一个例子:业务系统中,用户和角色的关系。在实际项目中,多对多关系通过中间表,看成两个一对多关联关系。

分析用户账户数据模型

一对一关联查询

需求

查询全部账户数据,并且关联查询账户所属的用户数据。

需求实现

新建一张account表

DROP TABLE IF EXISTS account;

CREATE TABLE account (
  accountId int(11) NOT NULL COMMENT '编号',
  UID int(11) default NULL COMMENT '用户编号',
  MONEY double default NULL COMMENT '金额',
  PRIMARY KEY  (accountId),
  KEY FK_Reference_8 (UID),
  CONSTRAINT FK_Reference_8 FOREIGN KEY (UID) REFERENCES user (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into account(accountId,UID,MONEY) values (1,46,1000),(2,45,1000),(3,46,2000);

实现方式一:resultType(了解)

分析sql语句中,包含了账户的数据和用户数据。我们增加一个实体类对象,其中包含有账户的属性和用户的属性,来完成结果集的映射。

实现方式二:resultMap

通过在实体类(账户和用户)之间,建立关联关系,则可以通过resultMap进行配置一对一关联关系。

建立Acount2User类,建立账户到用户的一对一关联关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fPs1DpfH-1582184761986)(media/1540555278041.png)]

声明mapper接口方法
package com.dao;

import com.po.Acount2User;

import java.util.List;

public interface Acount2UserDao {

    List<Acount2User> findO2O();

}
配置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="com.dao.Acount2UserDao">

    <!-- 配置账户到用户的一对一关联关系,说明:
        type:要映射的类型
        id:唯一标识名称,通过id引用该resultMap
        -->
    <resultMap id="o2omap" type="com.po.Acount2User">
        <!-- 配置账户主键字段对应关系 -->
        <id column="accountId" property="accountid"/>
        <!-- 配置账户的普通字段对应关系 -->
        <result column="UID" property="UID"/>
        <result column="MONEY" property="money"/>

        <!--建立user用户对象与查询的用户字段的映射关系-->
        <!--
        association 表示一对一关系映射配置
            property 对用账户对象中的user对象属性
            javaType 用户对象的类型(必须要指定)
            column   外键字段
                     一对一关系中账户表关联用户表的外键字段
        -->
        <association property="user" javaType="com.po.User" column="UID">
            <!-- 配置用户的主键字段对应关系 -->
            <id column="id" property="id"/>
            <!-- 配置用户的普通字段对应关系 -->
            <result column="username" property="username"/>
            <result column="birthday" property="birthday"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>

    <select id="findO2O" resultMap="o2omap">
        SELECT * FROM user u inner join account  a WHERE u.id = a.UID;
    </select>

</mapper>
测试
@Test
public void testO2O() throws Exception {
    InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    Acount2UserDao acount2UserDao  = sqlSession.getMapper(Acount2UserDao .class);
    List<Acount2User> acount2Users = acount2UserDao.findO2O();
    for (Acount2User acount2User : acount2Users) {
        System.out.println(acount2User);
    }
    sqlSession.close();
    resourceAsStream.close();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gzxADnp1-1582184761986)(media/1540555752754.png)]

一对多关联查询

需求

查询全部用户数据,并且关联查询出用户的所有账户数据。

修改User2AccountDao对象,建立用户到账户的一对多关联关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FuaUkR6V-1582184761986)(media/1540555849842.png)]

声明mapper接口方法

package com.dao;

import com.po.User2Account;

import java.util.List;

public interface User2AccountDao {

    List<User2Account> findO2M();
}

配置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="com.dao.User2AccountDao">


    <!-- 配置用户到账户的一对多关联关系,说明:
       type:要映射的类型
       id:唯一标识名称,通过id引用该resultMap
     -->
    <resultMap id="O2Mmap" type="com.po.User2Account">
        <!-- 配置用户的主键字段对应关系 -->
        <id column="id" property="id"/>
        <!-- 配置用户的普通字段对应关系 -->
        <result column="username" property="username"/>
        <result column="birthday" property="birthday"/>
        <result column="sex" property="sex"/>
        <result column="address" property="address"/>
        <!-- collection:配置一对多关联关系,说明:
        property:要映射的属性名称
        javaType:要映射的属性类型(可以指定,可以不指定,建议都指定)
        ofType:指定集合中存放的类型(必须要指定)
             -->
        <collection property="accounts" ofType="com.po.Account" column="UID">
            <!-- 配置账户的主键对应关系 -->
            <id column="accountId" property="accountid"/>
            <!-- 配置账户普通字段对应关系 -->
            <result column="UID" property="uid"/>
            <result column="MONEY" property="money"/>
        </collection>
    </resultMap>

    <select id="findO2M" resultMap="O2Mmap">
        select * from user u inner  join account a on u.id = a.UID
    </select>

</mapper>

测试

@Test
public void testO2M() throws Exception {
    InputStream resourceAsStream = App.class.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    User2AccountDao user2AccountDao  = sqlSession.getMapper(User2AccountDao.class);
    List<User2Account> user2Accounts = user2AccountDao.findO2M();
    for (User2Account user2Account : user2Accounts) {
        System.out.println(user2Account);
    }
    sqlSession.close();
    resourceAsStream.close();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ovxXHJjL-1582184761987)(media/1540556015543.png)]

多对多关联查询(双向的一对多)

多对多关联关系,可以通过中间表看成两个双向的一对多关联关系。

用户与角色多对多关系模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b2K38iH8-1582184761987)(media/1540556077961.png)]

准备环境

创建角色表和中间表

CREATE TABLE role (
    ID int(11) NOT NULL COMMENT '编号',
    ROLE_NAME varchar(30) default NULL COMMENT '角色名称',
    ROLE_DESC varchar(60) default NULL COMMENT '角色描述',
    PRIMARY KEY  (ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into role(ID,ROLE_NAME,ROLE_DESC) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');


DROP TABLE IF EXISTS user_role;

CREATE TABLE user_role (
    UID int(11) NOT NULL COMMENT '用户编号',
    RID int(11) NOT NULL COMMENT '角色编号',
    PRIMARY KEY  (UID,RID),
    KEY FK_Reference_10 (RID),
    CONSTRAINT FK_Reference_10 FOREIGN KEY (RID) REFERENCES role (ID),
    CONSTRAINT FK_Reference_9 FOREIGN KEY (UID) REFERENCES user (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into user_role(UID,RID) values (41,1),(45,1),(41,2);

剩下的自己参考一对多弄吧,骚年

发布了20 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ZHONGZEWEI/article/details/104412134