Mybatis 多對多

在前面的章節中,我們學習了一對多,多對一的關係,現在我們來看看 Mybatis 中的多對多應用。

mybatis3.0 添加了association和collection標籤專門用於對多個相關實體類數據進行級聯查詢,但仍不支持多個相關實體類數據的級聯保存和級聯刪除操作。因此在進行實體類多對多映射表設計時,需要專門建立一個關聯對象類對相關實體類的關聯關係進行描述。下文將以「User」和「Group"兩個實體類之間的多對多關聯映射爲例進行CRUD操作。

1、應用場景

假設項目中存在用戶和用戶組,從一個用戶讀取出它所在的用戶組,從一個用戶組也知道這個組內的所有用戶信息。

2、先做一些準備工作

我們首先在創建一個 java 工程,工程名稱爲:mybatis06-many2many(下載),還需要創建三張表,它們分別是用戶表 user,用戶組表 group 和 用戶組映射表 user_group ,一個戶用戶可以在多個用戶組中,一個用戶組中有多個用戶。項目工程結構如下:

Mybatis

user表的結構和數據:

CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(64) NOT NULL DEFAULT '',
`mobile` varchar(16) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


-- Records of user


INSERT INTO `user` VALUES ('1', 'yiibai', '13838009988');
INSERT INTO `user` VALUES ('2', 'User-name-1', '13838009988');

用戶組 group 表的結構和數據:

CREATE TABLE `group` (
`group_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`group_name` varchar(254) NOT NULL DEFAULT '',
PRIMARY KEY (`group_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


-- Records of group


INSERT INTO `group` VALUES ('1', 'Group-1');
INSERT INTO `group` VALUES ('2', 'Group-2');

用戶組映射表 user_group 的結構和數據:

CREATE TABLE `user_group` (
`user_id` int(10) unsigned NOT NULL DEFAULT '0',
`group_id` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- Records of user_group


INSERT INTO `user_group` VALUES ('1', '1');
INSERT INTO `user_group` VALUES ('2', '1');
INSERT INTO `user_group` VALUES ('1', '2');

從上面應該看出,用戶ID爲1同時在用戶組ID爲 1 和 2 中,而用戶ID爲 2 僅在一個用戶組ID爲1中。

2、創建表對應的 JavaBean 對象

這個例子中,我們需要在包 com.yiibai.pojo 下創建三個類,它們分別是: User.java 、Group.java 和 UserGroup.java,讓我們一個一個地來看它們的代碼,User.java 類的代碼如下:

package com.yiibai.pojo;

import java.util.List;

/**
* @describe: User
* @author: Yiibai
* @version: V1.0
* @copyright http://www.yiibai.com
*/
public class User {
private int id;
private String username;
private String mobile;
private List groups;
public List getGroups() {
return groups;
}
public void setGroups(List groups) {
this.groups = groups;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}

}

Group.java 類的代碼如下:

package com.yiibai.pojo;

import java.util.List;

/**
* @describe: Group
* @author: Yiibai
* @version: V1.0
* @copyright http://www.yiibai.com
*/
public class Group {
private int groupId;
private String groupName;
private List users;

public List<User> getUsers() {
    return users;
}
public void setUsers(List<User> users) {
    this.users = users;
}
public int getGroupId() {
    return groupId;
}
public void setGroupId(int groupId) {
    this.groupId = groupId;
}
public String getGroupName() {
    return groupName;
}
public void setGroupName(String groupName) {
    this.groupName = groupName;
}

}

UserGroup.java 類(用戶和用戶組的關係映射)的代碼如下:

package com.yiibai.pojo;

public class UserGroup {
private int userId;
private int groupId;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}

}

3、配置文件

在這一章節中,要用到的配置文件有四個,一個是 mybatis 的主配置文件:src/config/Configure.xml ,另外就是上面三個Bean類對應的配置文件,如,User.java 對應的配置文件 User.xml,等,我們先來看看 src/config/Configure.xml,其詳細配置信息如下:

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC" />
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/yiibai" />
            <property name="username" value="root" />
            <property name="password" value="" />
        </dataSource>
    </environment>
</environments>

<mappers>
    <!-- // power by http://www.yiibai.com -->
    <mapper resource="com/yiibai/maper/UserMaper.xml" />
    <mapper resource="com/yiibai/maper/GroupMaper.xml" />
    <mapper resource="com/yiibai/maper/UserGroupMaper.xml" />
</mappers>

Group.java 對應的 配置文件 src/com/yiibai/maper/Group.xml 的內容如下:

<parameterMap type="Group" id="parameterGroupMap">
    <parameter property="groupId"/>
    <parameter property="groupName"/>
</parameterMap>
<insert id="insertGroup" parameterMap="parameterGroupMap">
    INSERT INTO \`group\` (group\_name)
    VALUES(#{groupName}); 
</insert>

<resultMap type="Group" id="resultGroupMap\_1">
    <result property="id" column="id" />
    <result property="groupName" column="group\_name" />
    <collection property="users" column="group\_id"
        select="com.yiibai.maper.UserGroupMaper.getUsersByGroupId" />
</resultMap>
<select id="getGroup" resultMap="resultGroupMap\_1"
    parameterType="int">
    SELECT \*
    FROM \`group\`
    WHERE group\_id=#{id}
</select>

User.java 對應的配置文件 src/com/yiibai/maper/User.xml 的內容如下:

<insert id="insertUser" parameterMap="parameterUserMap">    
    INSERT INTO user(username,mobile)
    VALUES(#{username},#{mobile});
</insert>   

<resultMap type="User" id="resultUser">
    <result property="id" column="group\_id"/>
    <result property="name" column="name"/>
    <collection property="groups" column="id" select="com.yiibai.maper.UserGroupMaper.getGroupsByUserId"/>
</resultMap>

<select id="getUser" resultMap="resultUser" parameterType="int">
    SELECT \*
    FROM user
    WHERE id=#{id}
</select>    

UserGroup.java 對應的 配置文件 src/com/yiibai/maper/UserGroup.xml 的內容如下:

<insert id="insertUserGroup"  parameterMap="parameterUserGroupMap">
    INSERT INTO user\_group(user\_id, group\_id)
    VALUES(#{userId},#{groupId})
</insert>

<!-- 根據一個用戶組ID,查看這個用戶組下的所有用戶 -->
<resultMap type="User" id="resultUserMap\_2">
    <result property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="mobile" column="mobile"/>
</resultMap>

<select id="getUsersByGroupId" resultMap="resultUserMap\_2" parameterType="int">
    SELECT u.\*, ug.group\_id
    FROM user u, user\_group ug
    WHERE u.id=ug.user\_id AND ug.group\_id=#{group\_id}
</select>

<!-- 根據一個用戶ID,查看這個用戶所對應的組-->
<resultMap type="Group" id="resultGroupMap\_2">
    <result property="groupId" column="group\_id"/>
    <result property="groupName" column="group\_name"/>
</resultMap> 

<select id="getGroupsByUserId" resultMap="resultGroupMap\_2" parameterType="int">
    SELECT g.\*, u.user\_id
    FROM group g, user\_group u
    WHERE g.group\_id=u.group\_id AND u.user\_id=#{user\_id}
</select>

注:在上面的配置文件中,使用到了 和  標籤,關聯對應的 User 類和 Group類。

4、測試程序運行

到這裏,整個工作準備得已經差不多了,我們創建一個主類來測試上面程序,在 src 下創建一個 Main.java,代碼如下:

import java.io.Reader;
import java.text.MessageFormat;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.yiibai.maper.GroupMaper;
import com.yiibai.maper.UserGroupMaper;
import com.yiibai.maper.UserMaper;
import com.yiibai.pojo.Group;
import com.yiibai.pojo.User;
import com.yiibai.pojo.UserGroup;

public class Main {
private static SqlSessionFactory sqlSessionFactory;
private static Reader reader;

static {
    try {
        reader = Resources.getResourceAsReader("config/Configure.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static SqlSessionFactory getSession() {
    return sqlSessionFactory;
}

/\*\*
 \* @param args
 \*/
public static void main(String\[\] args) {
    // TODO Auto-generated method stub
    // testAddGroup();
    // testAddUser();
    // testAddUserGroup();
    testGetGroupAndUsers();

}

public static void testGetGroupAndUsers() {
    UserGroup userGroup = new UserGroup();
    SqlSession session = sqlSessionFactory.openSession();
    try {
        GroupMaper groupMaper = session.getMapper(GroupMaper.class);
        Group group = groupMaper.getGroup(1);
        System.out.println("Group => " + group.getGroupName());
        List<User> users = group.getUsers();
        for (User user : users) {
            System.out.println("\\t:" + user.getId() + "\\t"
                    + user.getUsername());
        }
    } finally {
        session.close();
    }
}

public static void testAddUserGroup() {
    UserGroup userGroup = new UserGroup();
    userGroup.setGroupId(1);
    userGroup.setUserId(2);
    SqlSession session = sqlSessionFactory.openSession();
    try {
        UserGroupMaper userGroupMaper = session
                .getMapper(UserGroupMaper.class);
        userGroupMaper.insertUserGroup(userGroup);

        session.commit();
    } finally {
        session.close();
    }

}

public static void testAddUser() {
    // TODO Auto-generated method stub
    SqlSession session = sqlSessionFactory.openSession();
    try {
        User user = new User();
        user.setUsername("User-name-1");
        user.setMobile("13838009988");
        UserMaper userMaper = session.getMapper(UserMaper.class);
        userMaper.insertUser(user);
        session.commit();
        // System.out.println(user.getGroupId());
    } finally {
        session.close();
    }
}

public static void testAddGroup() {
    // TODO Auto-generated method stub
    SqlSession session = sqlSessionFactory.openSession();
    try {
        Group group = new Group();
        group.setGroupName("用戶組-1");
        GroupMaper groupMapper = session.getMapper(GroupMaper.class);
        groupMapper.insertGroup(group);
        session.commit();
        System.out.println(group.getGroupId());
    } finally {
        session.close();
    }
}

}

運行上述程序,得出結果:

Group => Group-1
:1 yiibai
:2 User-name-1