Mybatis

【MyBatis】03 - MyBatis高级

2020-09-05  本文已影响0人  itlu

1. MyBatis中的连接池与事务控制

  1. 连接池 : 在实际开发中都会使用连接池,因为它可以减少获取连接所消耗的时间。

  2. 连接池是用于存储连接的容器;

  3. 容器其实就是一个集合对象,,该集合必须是线程安全的,不能两个线程拿到同一个连接;

  4. 该集合还必须实现队列的特性:先进先出。

1.1 MyBatis中的连接池

1.1.1 MyBatis连接池提供了3种方式的配置

  1. 配置位置:

主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。

  1. dataSource 标签中 type 属性的取值:

POOLED :采用传统javax.sql.DataSource规范中的连接池,MyBatis中有针对规范的实现。
UNPOOLED: 采用传统的获取连接的方式,虽然也实现了 javax.sql.DataSource接口,但是没有池的思想。
JNDI:采用服务器提供的JNDI技术实现来获取DataSource对象,不同的服务器所能拿到的DataSource是不一样的,同时涂如果不是Web或者Maven的war工程是不能使用的。我们实际开发中使用的是Tomcat服务器。采用的连接池就是DBCP连接池。

1.2 MyBatis中的事务

1.2.1 什么是事务?

  1. 如果一个包含多个步骤的业务操作被事务管理,那么这些操作要么同时成功要么同时失败。

  2. 案例 : 张三给李四转钱 。 第一步是查询张三账户余额是否大于 500 。 第二步张三账户减 500 。 第三步李四账户加500。如果当执行到第二步的时候出现异常,下面的步骤将不会再执行。如果该操作已经被事务管理,这三步操作,要么同时成功要么就同时失败。如果中间出现异常,将出现回滚操作。如果没有出现异常将提交事务。

1.2.2 事务的四大特性?

  1. 原子性: 事务是原子性的,原子是不可再分割的最小单位。要么同时成功要同时失败。是不可分割的最小操作单位。

  2. 持久性:当事务提交或者回滚之后,数据库会持久化的保存数据。

  3. 隔离性:多个事务之间相互独立。

  4. 一致性:事务操作前后数据总量不变 。

1.2.3 不考虑隔离性会产生的 3个 问题

  1. 脏读:个事务 ,读取到另一个事务中没有提交的数据 。

  2. 不可重复读: 在同一个事务中两次读取到的数据不一样。

  3. 幻读:一个事务去操作(DML增删改)数据表中所有数据 , 另一个事务添加了一条数据,则第一个事务查询不到自己的修改。

1.2.4 解决办法:四种隔离级别

  1. read uncommitted : 读未提交 。会产生的问题 是 脏读 、 不可重复度 、幻读 。

  2. read committed(Oracle默认的隔离级别) : 读已提交 。 会产生的问题 是 不可重复读 、 幻读。

  3. repeatable read(Mysql默认) :可重复读。 会产生的问题是 幻读。

  4. serializable : 串行化 。 可以解决所有的问题。

1.2.5 MyBatis中的事务是怎么样的

  1. 它是通过SqlSession对象的commit方法和rollback方法实现事务的提交和回滚操作。

1.2.6 MyBatis中事务提交的方式

  1. 在MyBatis中事务的提交方式默认是手动提交事务。
按照之前的方式创建一个新的Maven项目进行测试。直接复制使用代理dao方式实现CRUD项目进行修改。
  1. 创建好的项目码云地址 : https://gitee.com/lpzzzz/mybatis_datasource-tx_demo06

  2. 通过打印的日志查看MyBatis中事务的提交方式

mybatis事务默认的提交方式
  1. 设置MyBatis事务提交的方式为自动提交
向openSession方法传递一个Boolean值设置事务提交方式 设置事务的提交方式为自动提交

2. MyBatis的动态SQL语句

  1. 创建一个新的项目,复制上面数据库连接池和事务的项目。进行修改。删除不相关的增删改方法。

2.1 if 标签

  1. 创建一个根据用户条件进行查询的接口方法。
    /**
     * 根据指定的查询条件进行查询
     * @param user
     * @return
     */
    List<User> selectUserByCondition(User user);
  1. 在映射配置文件中编写sql实现查询,使用 if 标签拼接满足条件的查询条件 。需要使用 where 1 = 1 这个恒成立条件进行拼接操作。
  <!--根据查询条件进行查询-->
    <select id="selectUserByCondition" parameterType="user" resultMap="userMap">
        select * from user where 1 = 1
        <if test="userName != null">
            and username = #{userName}
        </if>
    </select>
  1. 编写测试类进行测试 :
  /**
    * 根据条件查询 User
    */
   @Test
   public void selectUserByCondition() {
       User u = new User();
       u.setUserName("老王");
       List<User> users = userDao.selectUserByCondition(u);
       for (User user : users) {
           System.out.println(user);
       }
   }

2.2 Where 标签

  1. where 标签的作用 : 就是不需要再加上 一个where 1 =1 恒成立的条件。

  2. 修改如下 :

 <!--使用where标签之后不需要再加上 where 1 = 1 的恒成立条件-->
    <select id="selectUserByCondition" resultMap="userMap" parameterType="user">
        select * from user
        <where>
            <if test="userName != null">
                and username = #{userName}
            </if>

            <if test="userSex != null">
                and sex = #{userSex}
            </if>
        </where>
    </select>

2.3 foreach 标签

  1. 需求:使用 in 进行子查询
  1. 在QueryVo 中添加一个 ids 属性,并重新生成 getter和 setter方法 :
/**
 * 实体包装类对象
 */
public class QueryVo {

    private User user;
 
    private List<Integer> ids;
  // 省略 getter 和 setter 方法 
}
  1. 编写根据ids 查询user的 接口方法
 /**
     * 根据ids 查询用户信息
     * @param queryVo
     * @return
     */
    List<User> selectUserByIds(QueryVo queryVo);
  1. 在UserDao.xml映射配置文件中编写sql如下 :
 <!--使用foreach标签实现子查询 注意这里的参数类型 需要实体类在domain包下 这样package 标签才能扫描到 否则就需要重新再加一个package包扫描。指定实体所在包 -->
    <select id="selectUserByIds" resultMap="userMap" parameterType="queryvo">
        select * from user
        <where>
            <if test="ids != null and ids.size() > 0">
                <foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>

由于我的QueryVo 实体不是在domain下 ,所以需要在全局配置文件中加上 package标签 配置条件实体所在的包路径。扫描该实体 :
<typeAliases> <package name="com.lyp.vo"/> </typeAliases>

  1. 编写测试类进行测试 :
   /**
    * 根据 ids 进行查询
    */
   @Test
   public void selectUserByIds() {
       QueryVo vo = new QueryVo();
       List<Integer> ids = new ArrayList<Integer>();
       ids.add(41);
       ids.add(42);
       ids.add(43);
       vo.setIds(ids);
       List<User> users = userDao.selectUserByIds(vo);
       for (User user : users) {
           System.out.println(user);
       }
   }
  1. foreach标签属性 :

collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符

2.4 使用 sql 标签抽取重复的 sql

  1. 可以抽取经常使用的 字段片段、使用频繁的sql语句 。
<!--对文件中常使用的sql片段和使用频繁的sql抽取出来-->
    <sql id="sqlFields">
        id, username,birthday,sex,address
    </sql>

<!---使用include根据id进行引用-->
  <select id="findAll" resultMap="userMap">
        <!-- select id as userId , username as userName , birthday as userBirthday ,sex as userSex , address as userAddress from user;-->
        select <include refid="sqlFields"/> from user;
   </select>
使用include 引用抽取的sql片段

2.5 项目地址

  1. 码云项目地址 : MyBatis中if 、where、 foreach、sql标签的使用

3. MyBatis中的多表操作

3.1 表之间的关系有几种 ?

3.1.1 一对一

  1. 一个人只能有一个身份证号。一个身份证号只能属于一个人。

3.1.2 一对多

  1. 用户和订单是一对多。

3.1.3 多对一

  1. 订单和用户是多对一的关系。

3.1.4 多对多

  1. 老师和学生就是多对多的关系。

3.1.5 特例

  1. 如果拿出每一个订单,它只属于一个用户。所以MyBatis就将多对一看成是 一对一。

3.2 MyBatis中的多表查询操作

3.2.1 步骤

  1. 首先,建立两张表。用户表、账户表。

  2. 建立两个实体类,用户实体类和账户实体类。

  3. 建立两个配置文件:用户配置文件、账户配置文件。

  4. 实现配置:当我们查询用户时,可以同时得到用户下包含的账户信息。当我们查询账户时,可以同时得到账户所属的用户信息。

3.2.2 创建Account 和 User 表

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` datetime default NULL COMMENT '生日',
  `sex` char(1) default NULL COMMENT '性别',
  `address` varchar(256) default NULL COMMENT '地址',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','北京'),(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),(46,'老王','2018-03-07 17:37:26','男','北京'),(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');

DROP TABLE IF EXISTS `account`;

CREATE TABLE `account` (
  `ID` INT(11) NOT NULL COMMENT '编号',
  `UID` INT(11) DEFAULT NULL COMMENT '用户编号',
  `MONEY` DOUBLE DEFAULT NULL COMMENT '金额',
  PRIMARY KEY  (`ID`),
  KEY `FK_Reference_8` (`UID`),
  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT  INTO `account`(`ID`,`UID`,`MONEY`) VALUES (1,46,1000),(2,45,1000),(3,46,2000);

3.2.3 创建项目

  1. 重新创建一个项目进行一对多查询。

  2. 复制之前项目的依赖到 pom.xml文件中 。

<packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>

3.2.4 创建实体类和接口

  1. 创建User实体类 和 UserDao接口 。创建Account账户实体类和AccountDao接口。
创建实体类和接口

3.2.5 在resources 类路径下创建全局配置文件 SqlMapConfig.xml文件

  1. 在resources 类路径下创建一个名为SqlMapConfig.xml的配置文件 :
  <?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>
    
    <properties
            url="file:///D:/work/idea-core/2020_08_29_Mybatis/mybatis_demo_CRUD_04/src/main/resources/jdbcConfiguration.properties"/>

    <typeAliases>
        <!--使用typeAlias 标签指定实体类的别名 简化书写-->
        <!--<typeAlias type="com.lyp.domain.User" alias="user"/>-->
        <!--使用package标签指定实体类的包名-->
        <package name="com.lyp.domain"/>
        <package name="com.lyp.vo"/>
    </typeAliases>

    <!--配置环境-->
    <environments default="mysql">
        <!--配置MySQL-->
        <environment id="mysql">
            <!--配置数据库的事务-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--<mapper resource="com/lyp/dao/UserDao.xml"/>-->
        <!--使用package标签指定持久层接口所在包-->
        <package name="com.lyp.dao"/>
    </mappers>
</configuration>

3.2.6 创建UserDao.xml 和AccountDao.xml配置文件。

  1. 在resources下创建 与 持久层接口包对应目录的 UserDao.xml 和AccountDao.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.lyp.dao.UserDao">


    <!--对文件中常使用的sql片段和使用频繁的sql抽取出来-->
    <sql id="sqlFields">
        id, username,birthday,sex,address
    </sql>

    <select id="findAll" resultType="user">
        <!-- select id as userId , username as userName , birthday as userBirthday ,sex as userSex , address as userAddress from user;-->
        select <include refid="sqlFields"/> from user;
    </select>

    <!--根据id查询用户信息-->
    <select id="findById" parameterType="int" resultType="user">
        select <include refid="sqlFields"/> from user where id = #{uid}
    </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="com.lyp.dao.AccountDao">


    <!--对文件中常使用的sql片段和使用频繁的sql抽取出来-->
    <sql id="sqlFields">
       id,uid,money
    </sql>

    <select id="findAll" resultType="account">
        <!-- select id as userId , username as userName , birthday as userBirthday ,sex as userSex , address as userAddress from user;-->
        select
        <include refid="sqlFields"/>
        from account;
    </select>

</mapper>

3.2.7 创建测试类进行测试

    private InputStream in;
    private UserDao userDao;
    private SqlSession session;


    /**
     * 初始化 会在测试方法执行之前执行
     *
     * @throws IOException
     */
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        session = factory.openSession();
        userDao = session.getMapper(UserDao.class);
    }

    /**
     * 销毁 会在测试方法执行之后执行
     *
     * @throws IOException
     */
    @After
    public void destroy() throws IOException {
        session.commit();
        if (session != null) {
            session.close();
        }

        if (in != null) {
            in.close();
        }
    }

3.3 查询账户的同时查询到用户信息(一对一 实体类继承的方式)

  1. 需求 : 在查询账户信息的同时查询到所属用户的名字和地址。
  -- 在查询账户信息的同时查询到所属用户的名称和地址
SELECT a.* , u.`username` , u.`address` 

FROM user u , account a 

WHERE u.id = a.`UID`;
  1. 编写实体类 AccountUser 继承Account。
public class AccountUser extends Account {
    private String username;
    private String address;
    // 省略 setter 和 getter 方法 
  
  /**
    注意这里的toString方法使用super调用了父类的toString方法
  */
    @Override
    public String toString() {
        return super.toString() + " ====> AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
  1. 编写AccountDao接口方法
/**
     *在查询账户信息的同时查询用户名称和地址
     * @return
     */
    List<AccountUser> findAllAccountUser();
  1. 在AccountDao.xml配置文件编写配置sql进行查询。
   <select id="findAllAccountUser" resultType="AccountUser">
        select a.* , u.username , u.address

        from account a,user u

        where a.uid = u.id
    </select>

3.4 查询账户的同时查询到用户信息(一对一 : 账户对应用户在Mybatis中的 多对一 算 一对一)

  1. 一对一 或者 多对一 中,从表的实体类和主表的实体类需要体现它们之间的关系。从表实体应该包含一个主表实体的对象引用。
  1. 修改Account实体类,添加一个对User的对象引用。
/**
 * 账户实体类
 * @author lyp
 */
public class Account {

    private Integer id;
    private Integer uid;
    private Double money;
    private User user;
    // 省略 setter 和 getter 方法
}
  1. 在Account中配置查询:
<resultMap id="accountUserMap" type="account">
      <!---这里id column 是起别名之后的-->
        <id property="id" column="aid"/>
        <result property="uid" column="uid"/>
        <result property="money" column="money"/>
        <!--
        一对一的关系映射:配置封装user的内容
            property : 实体类中的类名
            column : 关联的字段
            javaType : 封装的类型
        -->
        <association property="user" column="uid" javaType="user">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
        </association>
    </resultMap>
  1. 修改findAll查询:
 <!--使用关联查询-->
    <select id="findAll" resultMap="accountUserMap">
       select u.* , a.id as aid ,a.uid,a.money

        from user u , account a

        where a.uid = u.id
    </select>

3.5 一对多查询

  1. 一对多关系映射:主表实体包含对从表实体的集合引用。
 -- 一对多查询 使用左外连接查询 ,查询左表所有数据 ,和右表和左表有关联的数据
 SELECT  u.* , a.id AS aid ,a.uid ,a.`MONEY`
 
 FROM USER u LEFT JOIN account a ON u.id = a.`UID`;
  1. 修改User实体,在其中添加User实体对Account实体的集合引用。
/***
 * 用户实体类
 * @author lyp
 */
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<Account> accounts;
    // 省略 setter 和 getter  toString 方法 
}
  1. 修改UserDao.xml文件,创建一个resultMap。
  <resultMap id="userAccountMap" type="user">
        <id column="id" property="id"/>
        <result property="username" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
        <!--
            property : 实体类中属性的名称
            ofType : 集合中的类型
            javaType: 返回值封装为什么类型
        -->
        <collection property="accounts" ofType="account">
          <!--从表id字段与主表id字段冲突,使用了别名这里 的 column 需要与别名对应-->
            <id property="id" column="aid"/>
            <result property="uid" column="uid"/>
            <result property="money" column="money"/>
        </collection>
    </resultMap>

3.5.1 一对多 和 一对一 项目地址

  1. 项目地址 : 一对多 和 一对一 项目地址

3.6 多对多查询

3.6.1 用户和角色

  1. 建立两张表 用户表 、 角色表。让用户表和角色表具有多对多的关系。需要一张中间表,中间表中包含各自的主键。在中间表中是外键。
  1. 创建用户实体和角色实体。让用户实体和角色实体体现多对多的关系。各自包含对方的集合引用。

  2. 创建UserDao.xml 和 RoleDao.xml配置文件。

  3. 实现需求 :

3.6.2 创建一个新项目

  1. 复制一对多查询项目,删除有关Account的内容,剩余User的单表查询操作。

3.6.3 创建role 表 和 user_role表

DROP TABLE IF EXISTS `role`;

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);

3.6.4 创建Role实体类 + 持久层接口 + 配置文件 实现查询所有角色的操作

  1. 创建Role 实体类:注意这里实体类属性名称使用驼峰的命名方式。之后配置文件中就需要使用resultMap重新定义返回类型。
/**
 * @author lyp
 */
public class Role implements Serializable {

    private Integer id;
    private String roleName;
    private String roleDesc;
    // 省略setter 和 getter 方法 toString 方法 
}
  1. 创建RoleDao持久层接口 。编写查询所有的方法 。

/**
 * Role持久层接口
 *
 * @author lyp
 */
public interface RoleDao {

    /**
     * 查询所有角色
     * @return
     */
    List<Role> findAll();
}
  1. 创建RoleDao.xml配置文件:由于实体类属性名称和数据库字段名称不是一一对应的所以需要使用resultMap标签配置映射配置。
<?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.lyp.dao.RoleDao">

    <resultMap id="roleMap" type="role">
        <id property="id" column="id"/>
        <result property="roleDesc" column="role_desc"/>
        <result property="roleName" column="role_name"/>
    </resultMap>

    <sql id="roleFields">
        id,role_desc , role_name
    </sql>

    <select id="findAll" resultMap="roleMap">
        select
            <include refid="roleFields"/>
        from role;
    </select>
</mapper>

3.6.5 查询角色的时候同时获取到用户的信息 (多对多)

  1. 在 角色实体 中添加多对多映射集合引用,一个角色可以赋予多个角色。
/**
 * @author lyp
 */
public class Role implements Serializable {

    private Integer id;
    private String roleName;
    private String roleDesc;
    private List<User> users;
    // 省略 setter 和 getter toString 方法 
}
  1. 编写多表查询语句 :
 -- 编写多表查询语句 
 SELECT r.id AS rid , r.`ROLE_DESC` , r.`ROLE_NAME` ,u.*
 
 FROM role r 

LEFT JOIN user_role ur 

ON r.id = ur.`RID` 

LEFT JOIN USER u 
ON ur.uid = u.`id`;

3.配置RoleDao.xml :

<resultMap id="roleMap" type="role">
        <!--由于在查询语句中重名名了 role 表的id为rid 所以column 属性需要修改为rid-->
        <id property="id" column="rid"/>
        <result property="roleDesc" column="role_desc"/>
        <result property="roleName" column="role_name"/>
        <!--
         role 关联查询
         ofType为集合的类型
        -->
        <collection property="users" ofType="user">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="birthday" column="birthday"/>
            <result property="address" column="address"/>
            <result property="sex" column="sex"/>
        </collection>
    </resultMap>

    <sql id="roleFields">
        id,role_desc , role_name
    </sql>

    <select id="findAll" resultMap="roleMap">
         SELECT r.id AS rid , r.`ROLE_DESC` , r.`ROLE_NAME` ,u.*

         FROM role r

         LEFT JOIN user_role ur

         ON r.id = ur.`RID`

         LEFT JOIN USER u

         ON ur.uid = u.`id`;
    </select>

3.6.6 查询用户信息的时候同时查询到相应的角色信息 (多对多)

  1. 在User实体类中添加一个多对多的关系映射。对Role的集合引用。
/***
 * 用户实体类
 * @author lyp
 */
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<Role> roles;
    // 省略setter 和 getter toString方法
}
  1. 编写多对多查询的sql语句 : 左连接查询是查询左表所有数据 和 左表与 右表的交集
-- 编写 查询用户信息的同时查询其角色信息的多对多查询语句 
SELECT  u.* , r.id AS rid , r.`ROLE_NAME` , r.`ROLE_DESC`

FROM USER u  

LEFT JOIN user_role ur 

ON u.id = ur.`UID` 

LEFT JOIN role r 

ON ur.`RID` = r.`ID` ;
  1. 配置UserDao.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.lyp.dao.UserDao">

    <resultMap id="userAccountMap" type="user">
        <id column="id" property="id"/>
        <result property="username" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>

        <!--
            配置user与role的关联映射
            ofType为集合中值的类型
        -->
        <collection property="roles" ofType="role">
            <id property="id" column="rid"/>
            <result property="roleName" column="role_name"/>
            <result property="roleDesc" column="role_desc"/>
        </collection>
    </resultMap>

    <!--对文件中常使用的sql片段和使用频繁的sql抽取出来-->
    <sql id="sqlFields">
        id, username,birthday,sex,address
    </sql>

    <!--一对多查询,主表需要有一个对从表的引用-->
    <select id="findAll" resultMap="userAccountMap">
        SELECT  u.* , r.id AS rid , r.`ROLE_NAME` , r.`ROLE_DESC`

        FROM USER u

        LEFT JOIN user_role ur

        ON u.id = ur.`UID`

        LEFT JOIN role r

        ON ur.`RID` = r.`ID` ;
    </select>
</mapper>

3.6.7 项目地址

  1. 项目地址:Mybatis多对多查询demo地址
上一篇 下一篇

猜你喜欢

热点阅读