鍍金池/ 教程/ Java/ Mybatis 多對多
Mybatis表關(guān)聯(lián)多對一
MyBatis打印輸出SQL語句
Mybatis表關(guān)聯(lián)一對多
mybaits if標(biāo)簽語句
MyBatis整合Spring MVC
MyBatis動態(tài)SQL語句
MyBatis教程
MyBatis choose(when, otherwise)標(biāo)簽
Mybatis與Spring集成
MyBatis分頁
MyBatis SqlSessionDaoSupport實例
MyBatis where標(biāo)簽語句
Mybatis增刪改查(CURD)
Mybatis接口注解
Mybatis trim標(biāo)簽
Mybatis set標(biāo)簽
Mybatis 多對多
MyBatis環(huán)境配置及入門

Mybatis 多對多

在前面的章節(jié)中,我們學(xué)習(xí)了一對多,多對一的關(guān)系,現(xiàn)在我們來看看 Mybatis 中的多對多應(yīng)用。

mybatis3.0 添加了association和collection標(biāo)簽專門用于對多個相關(guān)實體類數(shù)據(jù)進(jìn)行級聯(lián)查詢,但仍不支持多個相關(guān)實體類數(shù)據(jù)的級聯(lián)保存和級聯(lián)刪除操作。因此在進(jìn)行實體類多對多映射表設(shè)計時,需要專門建立一個關(guān)聯(lián)對象類對相關(guān)實體類的關(guān)聯(lián)關(guān)系進(jìn)行描述。下文將以“User”和“Group"兩個實體類之間的多對多關(guān)聯(lián)映射為例進(jìn)行CRUD操作。

1、應(yīng)用場景

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

2、先做一些準(zhǔn)備工作

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


user表的結(jié)構(gòu)和數(shù)據(jù):

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 表的結(jié)構(gòu)和數(shù)據(jù):

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 的結(jié)構(gòu)和數(shù)據(jù):
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');

從上面應(yīng)該看出,用戶ID為1同時在用戶組ID為 1 和 2 中,而用戶ID為 2 僅在一個用戶組ID為1中。

2、創(chuàng)建表對應(yīng)的 JavaBean 對象

這個例子中,我們需要在包 com.yiibai.pojo 下創(chuàng)建三個類,它們分別是: 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<Group> groups;
	public List<Group> getGroups() {
		return groups;
	}
	public void setGroups(List<Group> 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<User> 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 類(用戶和用戶組的關(guān)系映射)的代碼如下:
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、配置文件

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

<?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>
	<typeAliases>
		<typeAlias alias="User" type="com.yiibai.pojo.User" />
		<typeAlias alias="UserGroup" type="com.yiibai.pojo.UserGroup" />
		<typeAlias alias="Group" type="com.yiibai.pojo.Group" />
	</typeAliases>

	<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>
</configuration>
Group.java 對應(yīng)的配置文件 src/com/yiibai/maper/Group.xml 的內(nèi)容如下:

<?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.yiibai.maper.GroupMaper">

	<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>
</mapper>	 

User.java 對應(yīng)的配置文件 src/com/yiibai/maper/User.xml 的內(nèi)容如下:

<?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.yiibai.maper.UserMaper">
	<parameterMap type="User" id="parameterUserMap">
		<parameter property="id"/>
		<parameter property="username"/>
		<parameter property="mobile"/>
	</parameterMap>
	
	<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>    
</mapper>
UserGroup.java 對應(yīng)的配置文件 src/com/yiibai/maper/UserGroup.xml 的內(nèi)容如下:
<?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.yiibai.maper.UserGroupMaper">
	<parameterMap type="UserGroup" id="parameterUserGroupMap">
		<parameter property="userId"/>
		<parameter property="groupId"/>
	</parameterMap>
	
	<insert id="insertUserGroup"  parameterMap="parameterUserGroupMap">
		INSERT INTO user_group(user_id, group_id)
		VALUES(#{userId},#{groupId})
	</insert>
	
	<!-- 根據(jù)一個用戶組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>
	
	<!-- 根據(jù)一個用戶ID,查看這個用戶所對應(yīng)的組-->
	<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>
</mapper>	 

注:在上面的配置文件中,使用到了 <association>和  <clollection>標(biāo)簽,關(guān)聯(lián)對應(yīng)的 User 類和 Group類。

4、測試程序運(yùn)行

到這里,整個工作準(zhǔn)備得已經(jīng)差不多了,我們創(chuàng)建一個主類來測試上面程序,在 src 下創(chuàng)建一個 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();
		}
	}
}

運(yùn)行上述程序,得出結(jié)果:

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