【MyBatis】03 - MyBatis高級

1. MyBatis中的連接池與事務(wù)控制

  1. 連接池 : 在實(shí)際開發(fā)中都會使用連接池,因?yàn)樗梢詼p少獲取連接所消耗的時間。

  2. 連接池是用于存儲連接的容器;

  3. 容器其實(shí)就是一個集合對象,,該集合必須是線程安全的,不能兩個線程拿到同一個連接;

  4. 該集合還必須實(shí)現(xiàn)隊(duì)列的特性:先進(jìn)先出。

1.1 MyBatis中的連接池

1.1.1 MyBatis連接池提供了3種方式的配置

  1. 配置位置:

主配置文件SqlMapConfig.xml中的dataSource標(biāo)簽,type屬性就是表示采用何種連接池方式。

  1. dataSource 標(biāo)簽中 type 屬性的取值:

POOLED :采用傳統(tǒng)javax.sql.DataSource規(guī)范中的連接池,MyBatis中有針對規(guī)范的實(shí)現(xiàn)。
UNPOOLED: 采用傳統(tǒng)的獲取連接的方式,雖然也實(shí)現(xiàn)了 javax.sql.DataSource接口,但是沒有池的思想。
JNDI:采用服務(wù)器提供的JNDI技術(shù)實(shí)現(xiàn)來獲取DataSource對象,不同的服務(wù)器所能拿到的DataSource是不一樣的,同時涂如果不是Web或者M(jìn)aven的war工程是不能使用的。我們實(shí)際開發(fā)中使用的是Tomcat服務(wù)器。采用的連接池就是DBCP連接池。

1.2 MyBatis中的事務(wù)

1.2.1 什么是事務(wù)?

  1. 如果一個包含多個步驟的業(yè)務(wù)操作被事務(wù)管理,那么這些操作要么同時成功要么同時失敗。

  2. 案例 : 張三給李四轉(zhuǎn)錢 。 第一步是查詢張三賬戶余額是否大于 500 。 第二步張三賬戶減 500 。 第三步李四賬戶加500。如果當(dāng)執(zhí)行到第二步的時候出現(xiàn)異常,下面的步驟將不會再執(zhí)行。如果該操作已經(jīng)被事務(wù)管理,這三步操作,要么同時成功要么就同時失敗。如果中間出現(xiàn)異常,將出現(xiàn)回滾操作。如果沒有出現(xiàn)異常將提交事務(wù)。

1.2.2 事務(wù)的四大特性?

  1. 原子性: 事務(wù)是原子性的,原子是不可再分割的最小單位。要么同時成功要同時失敗。是不可分割的最小操作單位。

  2. 持久性:當(dāng)事務(wù)提交或者回滾之后,數(shù)據(jù)庫會持久化的保存數(shù)據(jù)。

  3. 隔離性:多個事務(wù)之間相互獨(dú)立。

  4. 一致性:事務(wù)操作前后數(shù)據(jù)總量不變 。

1.2.3 不考慮隔離性會產(chǎn)生的 3個 問題

  1. 臟讀:個事務(wù) ,讀取到另一個事務(wù)中沒有提交的數(shù)據(jù) 。

  2. 不可重復(fù)讀: 在同一個事務(wù)中兩次讀取到的數(shù)據(jù)不一樣。

  3. 幻讀:一個事務(wù)去操作(DML增刪改)數(shù)據(jù)表中所有數(shù)據(jù) , 另一個事務(wù)添加了一條數(shù)據(jù),則第一個事務(wù)查詢不到自己的修改。

1.2.4 解決辦法:四種隔離級別

  1. read uncommitted : 讀未提交 。會產(chǎn)生的問題 是 臟讀 、 不可重復(fù)度 、幻讀 。

  2. read committed(Oracle默認(rèn)的隔離級別) : 讀已提交 。 會產(chǎn)生的問題 是 不可重復(fù)讀 、 幻讀。

  3. repeatable read(Mysql默認(rèn)) :可重復(fù)讀。 會產(chǎn)生的問題是 幻讀。

  4. serializable : 串行化 。 可以解決所有的問題。

1.2.5 MyBatis中的事務(wù)是怎么樣的

  1. 它是通過SqlSession對象的commit方法和rollback方法實(shí)現(xiàn)事務(wù)的提交和回滾操作。

1.2.6 MyBatis中事務(wù)提交的方式

  1. 在MyBatis中事務(wù)的提交方式默認(rèn)是手動提交事務(wù)。
按照之前的方式創(chuàng)建一個新的Maven項(xiàng)目進(jìn)行測試。直接復(fù)制使用代理dao方式實(shí)現(xiàn)CRUD項(xiàng)目進(jìn)行修改。
  1. 創(chuàng)建好的項(xiàng)目碼云地址 : https://gitee.com/lpzzzz/mybatis_datasource-tx_demo06

  2. 通過打印的日志查看MyBatis中事務(wù)的提交方式

mybatis事務(wù)默認(rèn)的提交方式
  1. 設(shè)置MyBatis事務(wù)提交的方式為自動提交
向openSession方法傳遞一個Boolean值設(shè)置事務(wù)提交方式
設(shè)置事務(wù)的提交方式為自動提交

2. MyBatis的動態(tài)SQL語句

  1. 創(chuàng)建一個新的項(xiàng)目,復(fù)制上面數(shù)據(jù)庫連接池和事務(wù)的項(xiàng)目。進(jìn)行修改。刪除不相關(guān)的增刪改方法。

2.1 if 標(biāo)簽

  1. 創(chuàng)建一個根據(jù)用戶條件進(jìn)行查詢的接口方法。
    /**
     * 根據(jù)指定的查詢條件進(jìn)行查詢
     * @param user
     * @return
     */
    List<User> selectUserByCondition(User user);
  1. 在映射配置文件中編寫sql實(shí)現(xiàn)查詢,使用 if 標(biāo)簽拼接滿足條件的查詢條件 。需要使用 where 1 = 1 這個恒成立條件進(jìn)行拼接操作。
  <!--根據(jù)查詢條件進(jìn)行查詢-->
    <select id="selectUserByCondition" parameterType="user" resultMap="userMap">
        select * from user where 1 = 1
        <if test="userName != null">
            and username = #{userName}
        </if>
    </select>
  1. 編寫測試類進(jìn)行測試 :
  /**
    * 根據(jù)條件查詢 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 標(biāo)簽

  1. where 標(biāo)簽的作用 : 就是不需要再加上 一個where 1 =1 恒成立的條件。

  2. 修改如下 :

 <!--使用where標(biāo)簽之后不需要再加上 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 標(biāo)簽

  1. 需求:使用 in 進(jìn)行子查詢
  1. 在QueryVo 中添加一個 ids 屬性,并重新生成 getter和 setter方法 :
/**
 * 實(shí)體包裝類對象
 */
public class QueryVo {

    private User user;
 
    private List<Integer> ids;
  // 省略 getter 和 setter 方法 
}
  1. 編寫根據(jù)ids 查詢user的 接口方法
 /**
     * 根據(jù)ids 查詢用戶信息
     * @param queryVo
     * @return
     */
    List<User> selectUserByIds(QueryVo queryVo);
  1. 在UserDao.xml映射配置文件中編寫sql如下 :
 <!--使用foreach標(biāo)簽實(shí)現(xiàn)子查詢 注意這里的參數(shù)類型 需要實(shí)體類在domain包下 這樣package 標(biāo)簽才能掃描到 否則就需要重新再加一個package包掃描。指定實(shí)體所在包 -->
    <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 實(shí)體不是在domain下 ,所以需要在全局配置文件中加上 package標(biāo)簽 配置條件實(shí)體所在的包路徑。掃描該實(shí)體 :
<typeAliases> <package name="com.lyp.vo"/> </typeAliases>

  1. 編寫測試類進(jìn)行測試 :
   /**
    * 根據(jù) ids 進(jìn)行查詢
    */
   @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標(biāo)簽屬性 :

collection:代表要遍歷的集合元素,注意編寫時不要寫#{}
open:代表語句的開始部分
close:代表結(jié)束部分
item:代表遍歷集合的每個元素,生成的變量名
sperator:代表分隔符

2.4 使用 sql 標(biāo)簽抽取重復(fù)的 sql

  1. 可以抽取經(jīng)常使用的 字段片段、使用頻繁的sql語句 。
<!--對文件中常使用的sql片段和使用頻繁的sql抽取出來-->
    <sql id="sqlFields">
        id, username,birthday,sex,address
    </sql>

<!---使用include根據(jù)id進(jìn)行引用-->
  <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 項(xiàng)目地址

  1. 碼云項(xiàng)目地址 : MyBatis中if 、where、 foreach、sql標(biāo)簽的使用

3. MyBatis中的多表操作

3.1 表之間的關(guān)系有幾種 ?

3.1.1 一對一

  1. 一個人只能有一個身份證號。一個身份證號只能屬于一個人。

3.1.2 一對多

  1. 用戶和訂單是一對多。

3.1.3 多對一

  1. 訂單和用戶是多對一的關(guān)系。

3.1.4 多對多

  1. 老師和學(xué)生就是多對多的關(guān)系。

3.1.5 特例

  1. 如果拿出每一個訂單,它只屬于一個用戶。所以MyBatis就將多對一看成是 一對一。

3.2 MyBatis中的多表查詢操作

3.2.1 步驟

  1. 首先,建立兩張表。用戶表、賬戶表。

  2. 建立兩個實(shí)體類,用戶實(shí)體類和賬戶實(shí)體類。

  3. 建立兩個配置文件:用戶配置文件、賬戶配置文件。

  4. 實(shí)現(xiàn)配置:當(dāng)我們查詢用戶時,可以同時得到用戶下包含的賬戶信息。當(dāng)我們查詢賬戶時,可以同時得到賬戶所屬的用戶信息。

3.2.2 創(chuàng)建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 創(chuàng)建項(xiàng)目

  1. 重新創(chuàng)建一個項(xiàng)目進(jìn)行一對多查詢。

  2. 復(fù)制之前項(xiàng)目的依賴到 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 創(chuàng)建實(shí)體類和接口

  1. 創(chuàng)建User實(shí)體類 和 UserDao接口 。創(chuàng)建Account賬戶實(shí)體類和AccountDao接口。
創(chuàng)建實(shí)體類和接口

3.2.5 在resources 類路徑下創(chuàng)建全局配置文件 SqlMapConfig.xml文件

  1. 在resources 類路徑下創(chuàng)建一個名為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 標(biāo)簽指定實(shí)體類的別名 簡化書寫-->
        <!--<typeAlias type="com.lyp.domain.User" alias="user"/>-->
        <!--使用package標(biāo)簽指定實(shí)體類的包名-->
        <package name="com.lyp.domain"/>
        <package name="com.lyp.vo"/>
    </typeAliases>

    <!--配置環(huán)境-->
    <environments default="mysql">
        <!--配置MySQL-->
        <environment id="mysql">
            <!--配置數(shù)據(jù)庫的事務(wù)-->
            <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標(biāo)簽指定持久層接口所在包-->
        <package name="com.lyp.dao"/>
    </mappers>
</configuration>

3.2.6 創(chuàng)建UserDao.xml 和AccountDao.xml配置文件。

  1. 在resources下創(chuàng)建 與 持久層接口包對應(yīng)目錄的 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>

    <!--根據(jù)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 創(chuàng)建測試類進(jìn)行測試

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


    /**
     * 初始化 會在測試方法執(zhí)行之前執(zhí)行
     *
     * @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);
    }

    /**
     * 銷毀 會在測試方法執(zhí)行之后執(zhí)行
     *
     * @throws IOException
     */
    @After
    public void destroy() throws IOException {
        session.commit();
        if (session != null) {
            session.close();
        }

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

3.3 查詢賬戶的同時查詢到用戶信息(一對一 實(shí)體類繼承的方式)

  1. 需求 : 在查詢賬戶信息的同時查詢到所屬用戶的名字和地址。
  -- 在查詢賬戶信息的同時查詢到所屬用戶的名稱和地址
SELECT a.* , u.`username` , u.`address` 

FROM user u , account a 

WHERE u.id = a.`UID`;
  1. 編寫實(shí)體類 AccountUser 繼承Account。
public class AccountUser extends Account {
    private String username;
    private String address;
    // 省略 setter 和 getter 方法 
  
  /**
    注意這里的toString方法使用super調(diào)用了父類的toString方法
  */
    @Override
    public String toString() {
        return super.toString() + " ====> AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
  1. 編寫AccountDao接口方法
/**
     *在查詢賬戶信息的同時查詢用戶名稱和地址
     * @return
     */
    List<AccountUser> findAllAccountUser();
  1. 在AccountDao.xml配置文件編寫配置sql進(jìn)行查詢。
   <select id="findAllAccountUser" resultType="AccountUser">
        select a.* , u.username , u.address

        from account a,user u

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

3.4 查詢賬戶的同時查詢到用戶信息(一對一 : 賬戶對應(yīng)用戶在Mybatis中的 多對一 算 一對一)

  1. 一對一 或者 多對一 中,從表的實(shí)體類和主表的實(shí)體類需要體現(xiàn)它們之間的關(guān)系。從表實(shí)體應(yīng)該包含一個主表實(shí)體的對象引用。
  1. 修改Account實(shí)體類,添加一個對User的對象引用。
/**
 * 賬戶實(shí)體類
 * @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"/>
        <!--
        一對一的關(guān)系映射:配置封裝user的內(nèi)容
            property : 實(shí)體類中的類名
            column : 關(guān)聯(lián)的字段
            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查詢:
 <!--使用關(guān)聯(lián)查詢-->
    <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. 一對多關(guān)系映射:主表實(shí)體包含對從表實(shí)體的集合引用。
 -- 一對多查詢 使用左外連接查詢 ,查詢左表所有數(shù)據(jù) ,和右表和左表有關(guān)聯(lián)的數(shù)據(jù)
 SELECT  u.* , a.id AS aid ,a.uid ,a.`MONEY`
 
 FROM USER u LEFT JOIN account a ON u.id = a.`UID`;
  1. 修改User實(shí)體,在其中添加User實(shí)體對Account實(shí)體的集合引用。
/***
 * 用戶實(shí)體類
 * @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文件,創(chuàng)建一個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 : 實(shí)體類中屬性的名稱
            ofType : 集合中的類型
            javaType: 返回值封裝為什么類型
        -->
        <collection property="accounts" ofType="account">
          <!--從表id字段與主表id字段沖突,使用了別名這里 的 column 需要與別名對應(yīng)-->
            <id property="id" column="aid"/>
            <result property="uid" column="uid"/>
            <result property="money" column="money"/>
        </collection>
    </resultMap>

3.5.1 一對多 和 一對一 項(xiàng)目地址

  1. 項(xiàng)目地址 : 一對多 和 一對一 項(xiàng)目地址

3.6 多對多查詢

3.6.1 用戶和角色

  1. 建立兩張表 用戶表 、 角色表。讓用戶表和角色表具有多對多的關(guān)系。需要一張中間表,中間表中包含各自的主鍵。在中間表中是外鍵。
  1. 創(chuàng)建用戶實(shí)體和角色實(shí)體。讓用戶實(shí)體和角色實(shí)體體現(xiàn)多對多的關(guān)系。各自包含對方的集合引用。

  2. 創(chuàng)建UserDao.xml 和 RoleDao.xml配置文件。

  3. 實(shí)現(xiàn)需求 :

  • 當(dāng)我們查詢用戶時,可以同時查詢到用戶所包含的角色信息。
  • 當(dāng)我們查詢角色時,可以同時查詢到角色所賦予的用戶信息。

3.6.2 創(chuàng)建一個新項(xiàng)目

  1. 復(fù)制一對多查詢項(xiàng)目,刪除有關(guān)Account的內(nèi)容,剩余User的單表查詢操作。

3.6.3 創(chuàng)建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,'院長','管理整個學(xué)院'),(2,'總裁','管理整個公司'),(3,'校長','管理整個學(xué)校');


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 創(chuàng)建Role實(shí)體類 + 持久層接口 + 配置文件 實(shí)現(xiàn)查詢所有角色的操作

  1. 創(chuàng)建Role 實(shí)體類:注意這里實(shí)體類屬性名稱使用駝峰的命名方式。之后配置文件中就需要使用resultMap重新定義返回類型。
/**
 * @author lyp
 */
public class Role implements Serializable {

    private Integer id;
    private String roleName;
    private String roleDesc;
    // 省略setter 和 getter 方法 toString 方法 
}
  1. 創(chuàng)建RoleDao持久層接口 。編寫查詢所有的方法 。

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

    /**
     * 查詢所有角色
     * @return
     */
    List<Role> findAll();
}
  1. 創(chuàng)建RoleDao.xml配置文件:由于實(shí)體類屬性名稱和數(shù)據(jù)庫字段名稱不是一一對應(yīng)的所以需要使用resultMap標(biāo)簽配置映射配置。
<?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. 在 角色實(shí)體 中添加多對多映射集合引用,一個角色可以賦予多個角色。
/**
 * @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 關(guān)聯(lián)查詢
         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 查詢用戶信息的時候同時查詢到相應(yīng)的角色信息 (多對多)

  1. 在User實(shí)體類中添加一個多對多的關(guān)系映射。對Role的集合引用。
/***
 * 用戶實(shí)體類
 * @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語句 : 左連接查詢是查詢左表所有數(shù)據(jù) 和 左表與 右表的交集
-- 編寫 查詢用戶信息的同時查詢其角色信息的多對多查詢語句 
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的關(guān)聯(lián)映射
            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 項(xiàng)目地址

  1. 項(xiàng)目地址:Mybatis多對多查詢demo地址
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容