
示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1、建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2、建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出来一对多的关系
3、建立两个配置文件
用户的配置文件
账户的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息
定义账户信息的实体类Account
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money; /*get set toString*/
}
User
public class User implements Serializable { private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
/*get set toString*/
}
用户的持久层接口IuserDao:
public interface IUserDao {
List<User> findAll();
User findUserById (Integer userId);
}
IAccountDao:
public interface IAccountDao {
/**
* 查询所有账户
* @return
*/
List<Account> findAll();
}
映射配置文件IUserDao.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.mkl.dao.IUserDao"> <!-- 查询所有 -->
<select id="findAll" resultType="user">
select * from user;
</select> <!-- 根据id查询用户 -->
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{uid}
</select> </mapper>
IAccountDao.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.mkl.dao.IAccountDao">
<!-- 查询所有账户信息-->
<select id="findAll" resultType="Account">
select * from account;
</select>
</mapper>
主配置文件:
<?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-->
<properties resource="jdbcConfig.properties"></properties> <!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<typeAliases>
<package name="com.mkl.domain"></package>
</typeAliases> <!--配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager> <!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.mkl.dao"></package>
</mappers>
</configuration>
一对一查询(多对一)
需求 :
查询所有账户信息,关联查询对应用户信息。
注意:
因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。
如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。
方式一 :
编写 Sql 语句
实现查询账户信息时,也要查询账户所对应的用户信息。
SELECT account.*, user.username, user.address
FROM account, user
WHERE account.uid = user.id ;
查询结果
定义 AccountUser 类
为了能够封装上面 SQL 语句的查询结果,定义 AccountCustomer 类中要包含账户信息同时还要包含用户信息
所以我们要在定义 AccountUser 类时可以继承Account 类。
public class AccountUser extends Account implements Serializable {
/*继承了Account中的信息*/
private String username;
private String address; /*get set super.toString+toString*/
}
账户的持久层接口 IAccountDao中添加方法
/**
* 查询所有账户 同时获取到当前账户的所属用户信息: 用户名称 地址
* @return
*/
List<AccountUser> findAllEnhance();
在 IAccountDao.xml 文件中添加相应的的查询配置信息
<!--增强的查询所有账户信息, 包含账户信息, 用户名称 地址-->
<select id="findAllEnhance" resultType="AccountUser">
select account.*, user.username as username,user.address as address
from account,user
where user.id=account.uid;
</select>
添加测试方法
/**
* 测试增强的查询所有账户信息, 包含账户信息, 用户名称 地址
*/
@Test
public void testFindAllAccountEnhance(){
List<AccountUser> accountUsers=accountDao.findAllEnhance ();
System.out.println (accountUsers);
}
方式二(常用):
让用户和账户的实体类能体现出来一对多的关系
使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。
一对一的关系映射 使用association标签
在从表实体类Account中添加主表实体的对象引用
从表实体应该包含一个主表实体的对象引用
//从表实体应该包含一个主表实体的对象引用
private User user; /*get set*/
IAccountDao 接口中的方法
/**
* 查询所有账户 同时获取账户的所属用户信息
* @return
*/
List<Account> findAll();
修改IAccountDao.xml 文件
<!--定义封装account和user的resultMap-->
<resultMap id="accountUserMap" type="account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
<!--一对一的关系映射, 配置封装User的内容-->
<association property="user" javaType="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
<result column="address" property="address"></result>
</association>
</resultMap> <!-- 查询所有账户信息-->
<select id="findAll" resultMap="accountUserMap">
select user.*,account.id as aid, account.uid ,account.money
from account,user
where user.id=account.uid;
</select>
一对多查询
需求:
查询所有用户信息及用户关联的账户信息。
分析:
用户信息和他的账户信息为一对多关系
并且查询过程中如果用户没有账户信息,此时也要将用户信息查询出来,我们想到了 左外连接查询 比较合适。
编写 SQL 语句 :
SELECT user.*, account.id AS aid,account.uid,account.money
FROM USER
LEFT JOIN account
ON user.id = account.uid ;
User 类加入 List<Account>
一对多关系映射, 主表实体应该包含从表实体的集合引用
private List<Account> accounts; /*get set*/
持久层接口IUserDao中的查询方法
/**
* 查询所有用户,同时获取出每个用户下的所有账户信息
* @return */
List<User> findAll();
修改持久层接口的映射配置文件IUserDao.xml
<resultMap id="userMap" type="user">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!--封装该用户下的账户信息到List-->
<!--collection是用于建立一对多中集合属性的对应关系, ofType用于指定集合元素的数据类型-->
<collection property="accounts" ofType="account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
</collection>
</resultMap> <!-- 查询所有 -->
<!--<select id="findAll" resultType="user">-->
<select id="findAll" resultMap="userMap">
SELECT user.*, account.id AS aid,account.uid,account.money
FROM USER
LEFT JOIN account
ON user.id = account.uid ;
</select>
collection 用于建立一对多中集合属性的对应关系 表示关联查询结果集
property="accounts" 关联查询的结果集存储在 User 对象的上哪个属性。
ofType="account" 指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。