MyBatis 入门学习2

本文详细介绍了MyBatis中的动态SQL语句,包括`<if>`、`<where>`和`<foreach>`标签的使用,以及如何进行多条件组合查询和范围查询。此外,还讲解了一对一、一对多和多对多关系的映射实现,通过实例展示了在SQL查询中的应用。最后,提到了如何通过提取重复SQL和使用`<sql>`标签实现SQL重用。
摘要由CSDN通过智能技术生成

MyBatis 学习2

MyBatis 的动态 SQL 语句

<if>

我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询, 如果 username 也不为空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。

数据库

在这里插入图片描述

User 实体类

public class User implements Serializable {

    private int userId;
    private String userName;
    private Date userBirthday;
    private String userAddress;
	//省略 getter、setter、toString 方法    
}

IUserDao.xml

 <!--多条件组合模糊查询-->
    <select id="findByUser" resultMap="userMap" parameterType="user">
        select * from t_user where 1=1
        <if test="userName != null">
            and username like #{userName}
        </if>
        <if test="userAddress != null">
            and address like #{userAddress}
        </if>
    </select>

测试方法

//多条件模糊查询
    @Test
    public void findByUser(){
        User user = new User();
        user.setUserName("%t%");
        user.setUserAddress("%广东%");
        List<User> all = userDao.findByUser(user);
        for (User u:all){
            System.out.println(u);
        }
    }

在这里插入图片描述

<where>

之前写 SQL 语句是这样的

<!--多条件组合模糊查询-->
    <select id="findByUser" resultMap="userMap" parameterType="user">
        select * from t_user where 1=1
        <if test="userName != null">
            and username like #{userName}
        </if>
        <if test="userAddress != null">
            and address like #{userAddress}
        </if>
    </select>

要加个 where 1=1 ,写多了就麻烦,就也可以用 <where> 标签

<select id="findByUser" resultMap="userMap" parameterType="user">
        select * from t_user
        <where>
            <if test="userName != null">
                and username like #{userName}
            </if>
            <if test="userAddress != null">
                and address like #{userAddress}
            </if>
        </where>
    </select>

<foreach>

使用多个 id 查询时的 SQL 语句时我们可能会这样写:

SELECT * FROM t_user WHERE  id IN (36,39)

给了个范围 36,39看看有没有 id =36 或者 39,那么这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。

在 QueryVO 中加入一个 List 集合用于封装参数

public class QueryVO implements Serializable {
    private User user;
    private List<Integer> ids;
    //省略 getter、setter 方法
    }

IUserDao.xml

<!--根据所给 id 范围查询-->
    <select id="findByIds" resultMap="userMap" parameterType="queryVO">
          select * from t_user
          <where>
              <if test="ids != null and ids.size>0">
                  <foreach collection="ids" open=" id in (" item="id" close=")" separator=",">
                      <!--item属性值与 #{这里的值要一样},如这里2个都为 id -->
                      #{id}
                  </foreach>
              </if>
          </where>
    </select>
  • collection:代表要遍历的集合元素,注意编写时不要写#{}
  • open:代表语句的开始部分
  • close:代表结束部分
  • item:代表遍历集合的每个元素,生成的变量名
  • sperator:代表分隔符

测试方法,这里查询id 是在(36,39) 这2个数的数据

//在所给的 id 范围查询
    @Test
    public void findByIds(){
        QueryVO queryVO = new QueryVO();
        List<Integer> ids = new ArrayList<Integer>();
        ids.add(36);
        ids.add(39);
        queryVO.setIds(ids);
        List<User> byIds = userDao.findByIds(queryVO);
        for (User u:byIds){
            System.out.println(u);
        }
    }

在这里插入图片描述

<sql>

SQL 中可将重复的 SQL 提取出来,使用时用 include 引用即可,最终达到 SQL 重用的目的。

<!--重用sql语句-->
    <sql id="defaultFind">
        select * from t_user
    </sql>

要用到 select * from t_user 的地方引用一下就可以了

<!--根据所给 id 范围查询-->
    <select id="findByIds" resultMap="userMap" parameterType="queryVO">
          <!--select * from t_user-->
          <include refid="defaultFind"></include>
          <where>
              <if test="ids != null and ids.size>0">
                  <foreach collection="ids" open=" id in (" item="id" close=")" separator=",">
                      <!--item属性值与 #{这里的值要一样},如这里2个都为 id -->
                      #{id}
                  </foreach>
              </if>
          </where>
    </select>

多表查询

多表关系

用户和订单:一对多

1个用户可以有多个订单,多个订单属于1个用户

人和身份证号:一对一

1个人有1个身份证号,1个身份证号对应1个人

老师和学生:多对多

1个学生有多个老师,1个老师有多个学生

在多对一中,把一个订单单独拿出来,它都只属于1个用户,所以 MyBatis 把多对一看作一对一。

一对一

演示例子:

Account 账号类

public class Account {
    private Integer id;	//账号id
    private Integer uid;	//账号的主人的id
    private Double money;	
    //省略 getter 、setter、toString 方法
    }

AccountUser 类

public class AccountUser extends Account {
    private String username;
    private String address;
    //省略 getter 、setter
    //这里的toString 方法为了观看效果,把父类(即 Account 类的 toString 方法也用了)
    @Override
    public String toString() {
        return super.toString()+"-----AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
    }

IAccountDao.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="com.rgb3.dao.IAccountDao">
  
    <!--查询所有账号信息和这些账号对应的人名和地址-->
    <select id="findAccountUsers" resultType="com.rgb3.domain.AccountUser">
        select account.*,user.username,user.address from t_account account , t_user user where account.uid = user.id;
    </select>
</mapper>

数据表 t_account

在这里插入图片描述

数据表t_user

在这里插入图片描述

测试方法

//查询所有账号信息和这些账号对应的人名和地址
    @Test
    public void findAccountUsers(){
        List<AccountUser> all = accountDao.findAccountUsers();
        for (AccountUser accountUser:all){
            System.out.println(accountUser);
        }
    }

在这里插入图片描述

提示:这种创建一个类继承另一个类来达到查询效果的方法实际中不常用,下面是另一种方法。

在Account 类里添加 User 类的对象引用

public class Account {
    private Integer id;
    private Integer uid;
    private Double money;
    //从表包含主表的一个实体对象引用
    private User user;
    //省略 setter、getter、toString 方法
    }

IAccountDao 接口添加一个方法演示

//查询所有账号信息和这些账号对应的人名和地址
    List<Account> findAccountUsers2();

IAccountDao.xml

添加定义封装 Account 和 User 的ResultMap

<!--定义封装 Account 和 User 的ResultMap-->
    <resultMap id="accountUserMap" type="Account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 一对一关系映射,封装 user 的内容 -->
        <association property="user" column="uid" javaType="user">
            <id property="userId" column="id"></id>
            <result property="userName" column="username"></result>
            <result property="userBirthday" column="birthday"></result>
            <result property="userAddress" column="address"></result>
        </association>
    </resultMap>
<!--查询所有账号信息和这些账号对应的人名和地址-->
<select id="findAccountUsers2" resultMap="accountUserMap">
        select user.*,account.id as aid,account.uid,account.money from t_account account , t_user user where account.uid = user.id;
    </select>

<association>里的 column 值表示用哪个字段获取 user,javaType 值表示User类,因为之前有起别名所以不用写全限定类名了,直接写了user

测试方法

//查询所有账号信息和这些账号对应的人名和地址
    @Test
    public void findAccountUsers2(){
        List<Account> all = accountDao.findAccountUsers2();
        for (Account accountUser:all){
            System.out.print(accountUser+"      ");
            System.out.println(accountUser.getUser());
        }
    }

在这里插入图片描述


一对多

一个人有多个账号

User 类

public class User implements Serializable {

    private int userId;
    private String userName;
    private Date userBirthday;
    private String userAddress;
    //一对多映射,主表实体应该包含从表实体的集合引用
    private List<Account> accounts;
    //省略 setter、getter、 toString方法
    }

Account 类

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //省略 setter、getter、 toString方法
    }

IUserDao 接口 添加1个演示方法

//一对多查询所有
    List<User> findUserAccountAll();

SQL 语句

SELECT u.*,account.id as aid,account.uid,account.money FROM  t_user u  LEFT OUTER JOIN t_account account ON account.uid=u.id

在数据库里查询是这样的:

在这里插入图片描述

IUserDao.xml

<!--一对多结果映射-->
    <resultMap id="userAccountMap" type="user">
        <id property="userId" column="id"></id>
        <result property="userName" column="username"></result>
        <result property="userBirthday" column="birthday"></result>
        <result property="userAddress" column="address"></result>
        <!--配置 user 对象的 accounts 集合映射-->
        <collection property="accounts" ofType="account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>
<!-- 一对多查询所有-->
    <select id="findUserAccountAll" resultMap="userAccountMap">
        <!--select * from t_user;-->
        SELECT u.*,account.id as aid,account.uid,account.money FROM  t_user u  LEFT OUTER JOIN t_account account ON account.uid=u.id
    </select>

<collection> 里的 ofType 属性指集合里元素的类型,所以这里是Account 类。

这里因为 t_user 表里有个 id 字段,t_account 表里也有个 id 字段,重复会不行,所以把 t_account 表里的 id 字段起了个别名 aid。

t_user 表

在这里插入图片描述

t_account 表

在这里插入图片描述

测试方法

//一对多查询全部
    @Test
    public void findUserAccountAll(){
        List<User> all = userDao.findUserAccountAll();
        for (User user : all){
            System.out.println(user);
            System.out.println(user.getAccounts());
            System.out.println("------------------------");
        }
    }

在这里插入图片描述


多对多

1个人可以有多个角色(如学生、儿子、工人),1种角色也可以赋予多个人。

演示查询角色获取角色所属的个人信息

创建角色表 t_role

在这里插入图片描述

角色和用户的中间表 t_user_role,注意这里使用了2个外键

CREATE TABLE `t_user_role`(
`uid` INT(10) NOT NULL,
`rid` INT (10) NOT NULL,
PRIMARY KEY (`uid`,`rid`),
CONSTRAINT `FK_rid` FOREIGN KEY (`rid`) REFERENCES `t_role` (`id`),
CONSTRAINT `FK_uid` FOREIGN KEY (`uid`) REFERENCES `t_user` (`id`)
)ENGINE= INNODB DEFAULT CHARSET=utf8;

在这里插入图片描述

用户表 t_user 就还是用之前的

在这里插入图片描述

创建 Role 角色类

public class Role implements Serializable {
    private Integer roleId;
    private String roleName;
    private String roleDesc;
    //多对多映射,1个角色可以赋予多个人
    private List<User> users;
    //省略getter、setter、toString 方法
    }

IRoleDao 接口

public interface IRoleDao {
    //查询所有
    List<Role> findAll();
}

IRoleDao.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="com.rgb3.dao.IRoleDao">

    <resultMap id="roleMap" type="role">
        <id property="roleId" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <collection property="users" ofType="user">
            <id property="userId" column="id"></id>
            <result property="userName" column="username"></result>
            <result property="userBirthday" column="birthday"></result>
            <result property="userAddress" column="address"></result>
        </collection>
    </resultMap>

    <!--多对多查询-->
    <select id="findAll" resultMap="roleMap">
        SELECT u.*,role.id AS rid,role_name,role_desc FROM t_role role
          LEFT OUTER JOIN t_user_role user_role ON role.id=user_role.rid
          LEFT OUTER JOIN t_user u ON u.id=user_role.uid
    </select>
</mapper>

提示:left 前面最好加空格,这样和上一句拼接起来就不会黏在一起。

RoleTest测试类

public class RoleTest {

    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IRoleDao roleDao;

    @Before//测试方式运行前运行
    public void init() throws Exception {
        //读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        factory = new SqlSessionFactoryBuilder().build(in);
        //用工厂生产SqlSession对象
        session = factory.openSession();
        //用SqlSession创建Dao接口的代理对象
        roleDao = session.getMapper(IRoleDao.class);
    }

    @After//测试方法运行后运行
    public void destroy() throws Exception {
        //提交事务
        session.commit();   //保存、修改、删除操作时,如果你没这步提交事务,数据是不能成功写入数据库的
        in.close();
        session.close();
    }

    //多对多查询
    @Test
    public void findAll(){
        List<Role> all = roleDao.findAll();
        for (Role role:all){
            System.out.println(role);
            System.out.println(role.getUsers());
        }
    }
}

SQL 语句在数据库里查询是这样的:

在这里插入图片描述

启动测试方法:

在这里插入图片描述

成功。

演示查询用户获取用户所拥有的角色,即1个用户可以有多种角色,这与上面的演示例子相似。

User 类

public class User implements Serializable {

    private int userId;
    private String userName;
    private Date userBirthday;
    private String userAddress;
	//多对多映射,1个用户可以有多种角色
    private List<Role> roles;
    //省略getter、setter、toString 方法
    }

IUserDao 接口添加演示方法

//多对多查询,1个人有多种角色
    List<User> findUserRolesAll();

IUserDao.xml

<!--多对多结果映射,1个用户有多种角色-->
    <resultMap id="userRoleMap" type="user">
        <id property="userId" column="id"></id>
        <result property="userName" column="username"></result>
        <result property="userBirthday" column="birthday"></result>
        <result property="userAddress" column="address"></result>
        <collection property="roles" ofType="role">
            <id property="roleId" column="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
    </resultMap>
    <!--多对多映射查询,1个用户可以有多种角色-->
    <select id="findUserRolesAll" resultMap="userRoleMap">
        <!--select * from t_user;-->
        SELECT u.*,role.id AS rid,role_name,role_desc FROM t_user u
          LEFT OUTER JOIN t_user_role user_role ON u.id=user_role.uid
          LEFT OUTER JOIN t_role role ON role.id=user_role.rid
    </select>

SQL 语句在数据库查询是这样的:

在这里插入图片描述

UserAccountTest 测试类添加测试方法

//多对多查询,1个人有多种角色
    @Test
    public void findUserRolesAll(){
        List<User> all = userDao.findUserRolesAll();
        for (User user : all){
            System.out.println(user);
            System.out.println(user.getRoles());
            System.out.println("------------------------");
        }
    }

在这里插入图片描述
完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值