MyBatis框架——Second Day

目录

一,MyBatis 连接池的配置

事务

二,动态SQL语句

动态SQL语句之if标签

演示if标签

动态SQL语句之foreach标签

foreach标签演示

Set 标签

三,抽取重复的SQL代码片段

四,多表查询

1.实体之间的关系

2.多表查询准备步骤

3.建立两张表一张用户表一张账户表

4.建立两张表对应的实体类

5.提供用户和账户的接口

6.提供用户和账户的映射文件

7.编写核心配置文件

8.我们先单表测试一下查询所有账户

9.当我们单表查询测试没有问题后,我们接下来进行多表查询

10.我们看一下在程序中进行查询,查询该账户所对应的用户信息,该怎么配置和编写

11. 接下来,再账户的接口中提供相应的方法

12.在账户的映射文件中编写多表查询的配置

13.测试

14.说明:采用这种继承的方式进行多表查询不常用,仅作了解

使用开发中常用的方式进行多表查询

1.首先我们在多表对应的实体类中,维护一个单表一方的实体类对象

2.在多表实体类的 IAccountDao.xml 映射文件中,进行一对一关系的配置

多表查询之一对多的查询,也就是一个用户可以有很多个账户

1.我在单表实体类中提供一个集合来描述这个一对多的关系,集合里面装的就是多个账户

2.在单表实体类的 IUserDao.xml 映射文件中,进行配置

3.编写sql语句,查询所有用户对应的账户信息,如果该用户没有账户信息以null展示

4. 修改查询所有用户的配置,把返回类型修改为我们配置的映射关系,以及把sql语句粘贴过来

5.测试

多表查询之多对多

1.多对多的处理

2.建立两张表:用户表,角色表

3.建立用户和角色的实体类

4.提供用户和角色的接口

5.提供接口对应的映射文件

6.核心配置文件还是之前的,就不用动了

7.下来,我们查询所有角色有哪些用户在使用

8.sql 语句编写好后,我们在实体类中来体现多对多的关系

9.在角色的接口中提供方法

10.在角色接口的 IRoleDao.xml 映射文件中进行配置

11.把配置查询的返回类型,以及sql语句

12.测试

下来就是查询该用户有哪些角色

1.在用户的接口中提供方法

2.在用户的实体类中,维护一个集合,用来描述多对多的关系

3.修改SQL语句

4.在IUserDao.xml 映射文件中编写配置

5.测试


一,MyBatis 连接池的配置

连接池:相当于一个容器,会提前初始化一定数量的连接对象,以便重复使用
1、我们在实际开发中都会使用连接池。因为它可以减少我们获取连接所消耗的时间。
 mybatis中的连接池
 mybatis连接池提供了3种方式的配置:
    配置的位置:
    主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。
type属性的取值:
    POOLED   采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
    UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
​

事务

mybatis中的事务
    什么是事务(很多步骤,是一个整体不可再分割,组成事务的每一个步骤,要么同时成功,要么同时失败)
    事务的四大特性ACID
    不考虑隔离性会产生的3个问题
    解决办法:四种隔离级别  
​
mybatis中的事务 
它是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚
如果我们不想手动提交事务,可以在创建SqlSession对象时传入true,表示自动提交事务
 SqlSession session = factory.openSession(true); 

二,动态SQL语句

Mybatis 的动态 SQL 语句 
Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,
有些时候业务逻辑复杂时,我们的 SQL 是动态变 化的,
此时在前面的学习中我们的 SQL 就不能满足要求了

动态SQL语句之if标签

我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。
比如在 id 如果不为空时可以根据 id 查询, 
如果 username 不同空时还要加入用户名作为条件。
这种情况在我们的多条件组合查询中经常会碰到。
​
<select id="findByUser" resultType="user" parameterType="user">  
        select * from user where 1=1 
    <if test="username!=null and username != '' ">   
        and username like #{username}  
    </if> 
    <if test="address != null">   
        and address like #{address}  
    </if>    
</select> 
​
注意:<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。 
另外要注意 where 1=1 的作用~

演示if标签

1.在接口中提供一个方法,根据性别和年龄去查询用户
 public interface IUserDao {
    //根据姓名和性别去查询用户
    List<User> selectUserByNameAndSex(User user);
}
​
2.在映射文件中进行配置
  
  <!--根据姓名和性别去查询 where 1=1 是为了后面好拼接 and  -->
    <select id="selectUserByNameAndSex" resultType="user" parameterType="user">
        select * from user where 1=1
        <if test="username!='' and username!=null">
            and username=#{username}
        </if>
        <if test="sex!='' and sex!=null">
            and sex=#{sex}
        </if>
    </select>
    
    说明:<if>标签的 test 属性中写的是对象的属性名
    
 3.测试 :
 @Test
    public void testLikeByVO() {
        IUserDao dao = sqlSession.getMapper(IUserDao.class);
        User user = new User();
        user.setUsername("沈某某");
       user.setSex("男");
        List<User> list = dao.selectUserByNameAndSex(user);
​
        for (User user1 : list) {
​
            System.out.println(user1);
        }
    }
    
4:问题:就是单纯用if标签来拼接条件,我们在写条件的时候,得把 where 1=1 写上 麻烦
那能不能 不写where 和 1=1 呢? 可以 那就得使用一个标签叫where标签
​
5.所以我们可以写成下面这样
​
  <!--根据姓名和性别去查询-->
    <select id="selectUserByNameAndSex" resultType="user" parameterType="user">
        select * from user  
        <where>
          <if test="username!='' and username!=null">
              and username=#{username}
          </if>
          <if test="sex!='' and sex!=null">
              and sex=#{sex}
          </if>
     </where>
 说明:使用了where标签后,我们的查询语句后面就可以不用写where 1=1

动态SQL语句之foreach标签

传入多个 id 查询用户信息,用下边两个 sql 实现:
 SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16) 
SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16) 
 
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。 这样我们将如何进行参数的传递?
在 QueryVo 中加入一个 List 集合用于封装参数 
public class QueryVo implements Serializable { 
 
 private List<Integer> ids;
​
}
​

foreach标签演示

1.在接口中提供一个根据多个id查询出多个用户
public interface IUserDao {
    //根据多个id查询出多个用户
    List<User> selectUserByIDS(QueryVO vo);
    //说明:我们的传入参数是QueryVO 也就是说,我们在QueryVO中提供一个集合,集合里面添加多个id
}
​
2.在QueryVO 中提供一个属性 是集合类型的
  public class QueryVO {
    User user;
    List<Integer> list;
    //get set 方法略 自己补上
   }
   
   
3.在映射文件中编写配置
​
   <!--根据多个id查询出多个用户  SELECT * FROM USER WHERE id IN(50,51,52);-->
     <select id="selectUserByIDS" resultType="user" parameterType="org.westos.domain.QueryVO">
        select * from user
        <where>
            <foreach collection="list" open="id in(" close=")" item="uid" separator=",">
                #{uid}
            </foreach>
        </where>
     </select>
     
 foreach标签中的属性说明: 
 collection:代表要遍历的集合元素,注意编写时不要写#{}  
open:代表语句的开始部分 
 close:代表结束部分
 item:当前遍历的集合中的元素
 separator:分隔符
 
 4.测试:
     @Test
    public void testUerByIDS() {
        IUserDao dao = sqlSession.getMapper(IUserDao.class);
        List<Integer> list = Arrays.asList(50, 51, 52);
        QueryVO queryVO = new QueryVO();
        queryVO.setList(list);
        List<User> users = dao.selectUserByIDS(queryVO);
        for (User user : users) {
            System.out.println(user);
        }
    }
    
  5.当然严谨期间你可以在遍历集合的时候,使用if标签对集合进行判断,当集合长度大于0并且集合不为空再去遍历集合
  <!--根据多个id查询出多个用户-->
     <select id="selectUserByIDS" resultType="user" parameterType="org.westos.domain.QueryVO">
        select * from user
        <where>
          <if test="list.size()>0 and list!=null">
              <foreach collection="list" open="id in(" close=")" item="uid" separator=",">
                  #{uid}
              </foreach>
          </if>
        </where>
     </select>
    

Set 标签

<update id="update1" parameterType="com.javacode2018.chat05.demo8.model.UserModel">
    UPDATE t_user 
    <set>
        <if test="name!=null">
            name = #{name},
        </if>
        <if test="age!=null">
            age = #{age},
        </if>
    </set>
    <where>
        <if test="id!=null">
            AND id = #{id}
        </if>
    </where>
</update>

我们将sql中的set去掉了,加了个set元素,set元素会内部嵌套的sql进行处理,将这部分sql前后的逗号给去掉并在前面加上set

当预期id和age的时候,生成的sql:

UPDATE t_user SET age = ? where id = ?

三,抽取重复的SQL代码片段

1.我们在映射文件中编写增删改查的配置时,写的一些SQL语句有一些片段是重复的 比如 select * from user
那么我们可以把这些重复的sql代码抽取处理,就可以 复用
​
2. 我们在映射文件中可以使用一个sql标签来抽象重复的sql代码
​
 <!--id 就是给sql片段起个名字,别的地方通过id来引用-->
    <sql id="mysql">
        select * from user  <!--注意:后面不要写分号-->
    </sql>
​
​
3.在其他地方,有使用到select * from user 这条语句的地方,就可以通过id来引用,引用要使用一个标签
  <select id="findAll" resultType="user">
            <!--查询所有 就可以引用抽取的sql代码片段-->
        <include refid="mysql"></include>
    </select>
    
        在比如下面也可以引用sql代码片段
       <!--根据姓名和性别去查询-->
    <select id="selectUserByNameAndSex" resultType="user" parameterType="user">
        <include refid="mysql"></include>
        <where>
            <if test="username!='' and username!=null">
                and username=#{username}
            </if>
            <if test="sex!='' and sex!=null">
                and sex=#{sex}
            </if>
        </where>
​
    </select>
​

四,多表查询

1.实体之间的关系

表之间的关系有几种:一对多,多对一 ,一对一,多对多
    举例:
        用户和订单就是一对多
        订单和用户就是多对一
            一个用户可以下多个订单
            多个订单属于同一个用户
        人和身份证号就是一对一
            一个人只能有一个身份证号
            一个身份证号只能属于一个人
​
        老师和学生之间就是多对多
            一个学生可以被多个老师教过
            一个老师可以交多个学生
    特例:
        用户和订单就是一对多
        如果拿出每一个订单,他都只能属于一个用户。
        所以Mybatis就把多对一看成了一对一。
    

2.多表查询准备步骤

示例:用户和账户
            一个用户可以有多个账户
            一个账户只能属于一个用户(多个账户也可以属于同一个用户)
        步骤:
            1、建立两张表:用户表,账户表
                让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
            2、建立两个实体类:用户实体类和账户实体类
                让用户和账户的实体类能体现出来一对多的关系
            3、建立两个配置文件
                用户的配置文件
                账户的配置文件
            4、实现配置:
                当我们查询用户时,可以同时得到用户下所包含的账户信息
                当我们查询账户时,可以同时得到账户的所属用户信息
​

3.建立两张表一张用户表一张账户表

用户表我们在第一天的时候,已经建立好,账户表,那第一天的资料中有
那么用户表和账户表之间是一对用的关系,且添加了外键约束

4.建立两张表对应的实体类

public class User implements Serializable {
 
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
     //get set 方法略 自己补上
}
​
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //get set 方法略 自己补上
 }
​
注意:实体类的属性名和表的字段名保持一致

5.提供用户和账户的接口

//提供用户的接口,把我们前的操作保留两个
public interface IUserDao {
    //查询所有用户
    List<User> findAll();
    //根据id查询一个用户
    User selectUserById(Integer id);
}
​
​
//提供账户的接口
public interface IAccountDao {
    //等会再添加增删改查的操作的方法
}
​

6.提供用户和账户的映射文件

//用户的映射文件
<?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="org.westos.dao.IUserDao">
    <!--查询所有用户-->
    <select id="findAll" resultType="user">
        select * from user;
    </select>
    <!--查询单个用户-->
    <select id="selectUserById" resultType="org.westos.domain.User" parameterType="INT">
        select * 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="org.westos.dao.IAccountDao">
   
</mapper>
​
注意:映射文件所在的文件夹层次结构,要和接口的包名保持一致,映射文件名和接口名保持一致
​
​

7.编写核心配置文件

注意:核心配置文件,引入dao接口的映射文件采用扫描对应包下的所有接口
​
<?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 resource="jdbcConfig.properties"></properties>
    <!--给实体类配置别名-->
    <typeAliases>
        <!--这是该给包下所有的实体类配置了别名-->
        <package name="org.westos.domain"></package>
    </typeAliases>
    <environments default="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>
    <!--引入dao接口的映射文件-->
    <mappers>
        <!--扫描该包下所有的dao接口对应的配置文件-->
        <package name="org.westos.dao"></package>
    </mappers>
</configuration>

8.我们先单表测试一下查询所有账户

1.我们在账户的接口中提供查询所有账户信息的方法
​
    public interface IAccountDao {
     List<Account> findAll();
    }
    
2. 编写账户的映射文件
   
<mapper namespace="org.westos.dao.IAccountDao">
    <select id="findAll" resultType="account">
        select * from account
    </select>
</mapper>
​
3.测试:单独写一个测试Account的测试类,使用@Before @After 注解来加载配置文件和释放资源
  
  @Test
    public void testFindAll(){
        IAccountDao dao = sqlSession.getMapper(IAccountDao.class);
        List<Account> list = dao.findAll();
        for (Account account : list) {
            System.out.println(account);
        }
    }
​

9.当我们单表查询测试没有问题后,我们接下来进行多表查询

1.我们要查询 所有账户所对应的用户信息
 我们先在小海豚中编写sql语句测试一下
 SELECT a.*,u.* FROM account a,USER u WHERE a.`UID`=u.`id`;
 通过上面的查询语句就可以查询出账户所属的用户信息 
 但是 账户表里有个字段叫 id  用户表里有个字段叫id  重名了,那我们可以给账户表里的id字段起个别名
 或者我们不展示用户表里的id字段 也可以
 可以写成下面的
SELECT a.*,u.`username`,u.`address` FROM account a,USER u WHERE a.`UID`=u.`id`;
 
也就是 用户表中,我只展示了姓名和地址两个字段,说明问题就行了 
 

10.我们看一下在程序中进行查询,查询该账户所对应的用户信息,该怎么配置和编写

1.因为我们多表查询出的数据既有账户信息还有用户信息,那么得将所有信息封装到一个实体类中,那账户的实体类
中没有用户的信息的字段,所以我们提供一个实体类,继承账户的实体,然后在子类里面,提供封装用户信息的字段
​
public class AccountUser extends Account{
    //我提供了两个字段,因为我们等会查询的时候,只查询user表的两个字段,当然你要查几个字段,你就在实体类中提供几个字段,我提供两个说明问题就行了
    private String username;
    private String address;
    //get set 方法略,自己补上
    
    //这里提供toString()方法,里面再调用一下父类的toString()方法,等会测试打印的时候,可以看到所有字段的信息
    @Override
    public String toString() {
        //调用一下父类的toString()
        return super.toString()+"  AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
​

11. 接下来,再账户的接口中提供相应的方法

public interface IAccountDao {
    //查询所有账户信息
    List<Account> findAll();
    //查询该账户所对应的用户信息 注意范型,是Account的子类,因为他里面的属性,加上从父类继承下来属性,就能封装下我们查询出来的数据
    List<AccountUser> findAccountAndUser();
}

12.在账户的映射文件中编写多表查询的配置

 <select id="findAccountAndUser" resultType="org.westos.domain.AccountUser">
        SELECT a.*, u.`username`, u.`address`
        FROM account a,
             USER u
        WHERE a.`UID` = u.`id`;
    </select>
    
 注意:返回类型是Account的子类,还有sql语句的编写   

13.测试

 @Test
    public void testFindAccountAndUser() {
        IAccountDao dao = sqlSession.getMapper(IAccountDao.class);
        List<AccountUser> list = dao.findAccountAndUser();
        for (AccountUser account : list) {
            System.out.println(account);
        }
    }
    
    

14.说明:采用这种继承的方式进行多表查询不常用,仅作了解

使用开发中常用的方式进行多表查询

1.采用继承的方式,不推荐使用。那么我们怎么能体现出这种一对一的关系呢?
​
2.我们在实体类中来体现这种一对一的关系
  

1.首先我们在多表对应的实体类中,维护一个单表一方的实体类对象

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //在多表实体类中,维护单表实体类的对象
    private User user;
    
    //get set 方法省略 自己补上
    
}    

2.在多表实体类的 IAccountDao.xml 映射文件中,进行一对一关系的配置

1.在配置之前,我们现在小海豚中编写sql语句测试一下 
  那么这次我们可以把 用户表的所有字段都展示完,账户表中的一个id字段名和用户表中的id字段名一样,
  我们给账户表中的id字段起个别名,sql语句如下:
  
  SELECT a.id AS aid,a.uid,a.money,u.* FROM account a,USER u WHERE a.`UID`=u.`id`;
  
  我们在映射文件中 就可以使用上面这条sql语句
  
2.接下来在多表实体类的映射文件中进行一对一映射关系的配置
   * 先使用resultMap表签 配置多表和实体类的映射关系
  *  然后使用association这个标签来配置一对一
​
   <!--配置多表实体类和表中字段的映射关系-->
    <resultMap id="myAccountMap" type="org.westos.domain.Account">
        <!--配置主键,注意表中的id字段起了别名就用别名-->
        <id property="id" column="aid"></id>
        <!--配置其他字段-->
        <result property="uid" column="uid"/>
        <result property="money" column="money"></result>
        <!--配置多表和主表的一对一的关系
            property="user" 多表实体类中维护的单表实体类的对象
            column="uid" 多表通过这个uid字段跟单表产生关联的关系
            javaType 通过账户查询出所属的用户信息,要封装到User实体类中
        -->
        <association property="user" column="uid" javaType="org.westos.domain.User">
            <!--配置主表和实体类的映射关系-->
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </association>
​
    </resultMap>
  
 3.  修改查询所有账户的配置的返回值类型,修改为我们配置的映射关系   resultMap="myAccountMap"
 
  <select id="findAll" resultMap="myAccountMap">
      
    </select>
    
 4.修改sql语句
 <select id="findAll" resultMap="myAccountMap">
    SELECT a.id AS aid,a.uid,a.money,u.* FROM account a,USER u WHERE a.`UID`=u.`id`;
 </select>
 
 5.测试:通过account.getUser();可以查看该账户对应的用户信息
 
    @Test
    public void testFindAll(){
        IAccountDao dao = sqlSession.getMapper(IAccountDao.class);
        List<Account> list = dao.findAll();
        for (Account account : list) {
            System.out.println(account);
            //获取该账户对应的用户信息
            User user = account.getUser();
            System.out.println(user);
        }
    }
   
   

多表查询之一对多的查询,也就是一个用户可以有很多个账户

1.我在单表实体类中提供一个集合来描述这个一对多的关系,集合里面装的就是多个账户

public class User implements Serializable {
 
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    /*在单表实体类中提供集合,来描述一对多的关系*/
    private List<Account> accounts;
    
     //get set 方法略 自己补上
     
  }   

2.在单表实体类的 IUserDao.xml 映射文件中,进行配置

* 使用resultMap标签 配置实体类和表的映射关系
* 使用collection标签 配置集合 
    collection标签 有两个属性 
        1. property   主表实体类中维护的那个集合
        2. ofType     集合中装的什么类型
​
​
<resultMap id="userMap" type="org.westos.domain.User">
        <!--配置主表和实体类的映射关系-->
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
​
        <!--
            property="accounts" 主表实体类中维护的那个集合
            ofType="org.westos.domain.Account" 集合中装的什么类型
        -->
        <collection property="accounts" ofType="org.westos.domain.Account">
            <!--配置主键,注意表中的id字段起了别名就用别名-->
            <id property="id" column="aid"></id>
            <!--配置其他字段-->
            <result property="uid" column="uid"/>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>

3.编写sql语句,查询所有用户对应的账户信息,如果该用户没有账户信息以null展示

在小海豚中编写sql语句测试好
​
-- 我要查询所有用户的账户信息,没有账户信息的以null展示,但是所有用户信息必须展示出来,
-- 内连接不行,因为内连接不符合条件的是不展示
-- 所以我们使用外连接
SELECT u.*,a.id AS aid,a.`MONEY`,a.`UID` FROM USER u LEFT OUTER JOIN account a ON u.`id`=a.`UID`;

4. 修改查询所有用户的配置,把返回类型修改为我们配置的映射关系,以及把sql语句粘贴过来

修改返回值类型 改为  resultMap="userMap"
​
<!--查询所有用户-->
    <select id="findAll" resultMap="userMap">
        SELECT u.*, a.id AS aid, a.`MONEY`, a.`UID`
        FROM USER u
                 LEFT OUTER JOIN account a ON u.`id` = a.`UID`;
    </select>

5.测试

     @Test
    public void testFindAll() throws IOException {
        //获取接口的代理对象
        IUserDao userDao = sqlSession.getMapper(IUserDao.class);
        //执行查询操作
        List<User> list = userDao.findAll();
        for (User user : list) {
            System.out.println(user);
            //获取该用户对应的账户信息
            List<Account> accounts = user.getAccounts();
            System.out.println(accounts);
        }
    }

多表查询之多对多

1.多对多的处理

    多对多的处理
    示例:用户和角色
            一个用户可以有多个角色 
            一个角色可以赋予多个用户
    步骤:
        1、建立两张表:用户表,角色表
        让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
        2、建立两个实体类:用户实体类和角色实体类
            让用户和角色的实体类能体现出来多对多的关系
            各自包含对方一个集合引用
        3、建立两个配置文件
            用户的配置文件
            角色的配置文件
        4、实现配置:
            当我们查询用户时,可以同时得到用户所包含的角色信息
            当我们查询角色时,可以同时得到角色的所赋予的用户信息  

2.建立两张表:用户表,角色表

因为用户和角色是多对多的关系,所以还需要建立一张中间表
建表语句,在第一天的资料中有,这里就省略了

3.建立用户和角色的实体类

 //用户的实体类
public class User implements Serializable {
 
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    //get set 方法略 自己补上
}  
​
​
//角色的实体类
public class Role implements Serializable {
    private Integer id;
    private String roleName;
    private String roleDesc;
    //get set 方法略 自己补上
}
​
注意:这里我故意没让角色实体类的属性名和表中的字段名保持一致,也就是提醒我们要配置映射

4.提供用户和角色的接口

public interface IUserDao {
    //查询所有用户
    List<User> findAll();
}
​
public interface IRoleDao {
    //查询所有角色对应的用户信息
    List<Role> findAll();
}
​

5.提供接口对应的映射文件

<?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>
    //里面等会再来编写
</mapper>

6.核心配置文件还是之前的,就不用动了

7.下来,我们查询所有角色有哪些用户在使用

1.我们现在小海豚中,把sql语句先测试好
 我们一步一步来编写sql语句 
 * 先查把角色表和中间表关联起来查询
 SELECT r.*,ur.* FROM role r LEFT OUTER JOIN user_role ur ON r.`id`=ur.`RID`;
 
 * 接着,上一步查询的数据里面还没有 用户的信息,所以再继续加入 user表查询
 SELECT r.*,u.* FROM role r LEFT OUTER JOIN user_role ur ON r.`id`=ur.`RID` LEFT OUTER JOIN USER u ON u.`id`=ur.`UID`
 注意:中间表的字段信息,不用,所以把ur.* 删掉,把 u.* 用户表的信息加上,中间表只是作为连接条件
 
 * 上面第二步查询出的字段中 这个角色表的id 和用户表的 id 重名了,所以我们给角色表的id字段起个别名
 所以sql 语句编写如下:
 SELECT r.id AS rid,r.`ROLE_NAME`,r.`ROLE_DESC`,u.* FROM role r LEFT OUTER JOIN user_role ur ON r.`id`=ur.`RID` LEFT OUTER JOIN USER u ON u.`id`=ur.`UID`
 

8.sql 语句编写好后,我们在实体类中来体现多对多的关系

1.我们在角色的实体类中提供一个集合,用来描述多对多的关系
​
public class Role implements Serializable {
    private Integer id;
    private String roleName;
    private String roleDesc;
    //提供一个集合,来描述多对多的关系,集合里面放的是User类
    private List<User> users;
    //get set 方法略 自己补上
 }   

9.在角色的接口中提供方法

public interface IRoleDao {
    //查询所有角色对应的用户信息
    List<Role> findAll();
}

10.在角色接口的 IRoleDao.xml 映射文件中进行配置

* 配置角色实体类和角色表的映射关系,注意我的角色实体类中的属性名没有和表中的字段名保持一致,所以配的时候注意
collection 标签中的两个属性:
* property="users" 角色表中维护的那个集合对象
* ofType="org.westos.domain.User" 集合中装的什么类型
​
​
 <resultMap id="roleMap" type="org.westos.domain.Role">
        <!--配置实体类和表的映射关系
          注意 id 在sql语句中起了别名,就配置别名
        -->
        <id property="id" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <!--配置多对多的关系-->
        <collection property="users" ofType="org.westos.domain.User">
            <!--配置user表和实体类的映射关系-->
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </collection>
    </resultMap>

11.把配置查询的返回类型,以及sql语句

1.把我们刚才测试好的sql语句粘贴进来,以及返回类型修改为我们配置的映射id名
    <select id="findAll" resultMap="roleMap">
        SELECT r.id AS rid, r.`ROLE_NAME`, r.`ROLE_DESC`, u.*
        FROM role r
                 LEFT OUTER JOIN user_role ur ON r.`id` = ur.`RID`
                 LEFT OUTER JOIN USER u ON u.`id` = ur.`UID`
    </select>

12.测试

    * @Before @After 中的代码略了 ,注意一下
    
    @Test
    public void testFindAll(){
        IRoleDao dao = sqlSession.getMapper(IRoleDao.class);
        List<Role> list = dao.findAll();
        for (Role role : list) {
            System.out.println(role);
            //获取角色的所属用户
            List<User> users = role.getUsers();
            System.out.println(users);
        }
    }

下来就是查询该用户有哪些角色

1.在用户的接口中提供方法

public interface IUserDao {
    //查询该用户都有哪些角色
    List<User> findAll();
}
​

2.在用户的实体类中,维护一个集合,用来描述多对多的关系

public class User implements Serializable {
 
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    //提供一个集合用来描述一个用户有多个角色
    private List<Role> roles;
   //get set 方法略,自己补上   
}

3.修改SQL语句

把我们刚才查询该角色属于哪个用户用的左外连接,修改成右外连接,
就可以查询出,所有用户有哪些角色
 SELECT r.id AS rid, r.`ROLE_NAME`, r.`ROLE_DESC`, u.*
        FROM role r
                 RIGHT JOIN user_role ur ON r.`ID` = ur.`RID`
                 RIGHT JOIN USER u ON ur.`UID` = u.`id`

4.在IUserDao.xml 映射文件中编写配置

<resultMap id="userMap" type="org.westos.domain.User">
        <!--配置主表和实体类的映射关系-->
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
​
        <!--
            property="roles" 用户实体类中维护的集合
            ofType="org.westos.domain.Role" 集合中装的什么类型
        -->
        <collection property="roles" ofType="org.westos.domain.Role">
            <!--配置实体类和表的映射关系
      注意 id 在sql语句中起了别名,就配置别名
    -->
            <id property="id" column="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
    </resultMap>
    
    <!--查询所有用户都有哪些角色-->
    <select id="findAll" resultMap="userMap">
        SELECT r.id AS rid, r.`ROLE_NAME`, r.`ROLE_DESC`, u.*
        FROM role r
                 RIGHT JOIN user_role ur ON r.`ID` = ur.`RID`
                 RIGHT JOIN USER u ON ur.`UID` = u.`id`
    </select>

5.测试

   @Test
    public void testFindAll() throws IOException {
        //获取接口的代理对象
        IUserDao userDao = sqlSession.getMapper(IUserDao.class);
        //执行查询操作
        List<User> list = userDao.findAll();
        for (User user : list) {
            System.out.println(user);
            //获取该用户右哪些角色
            List<Role> roles = user.getRoles();
            System.out.println(roles);
​
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jmh-Ethereal

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值