声明
本博客是看了黑马的课程之后总结来的,感兴趣的可以去看原教学视频,讲得挺好。 另外,各位读者有什么建议最好是留言,一起进步,加油!
1.一对一(多对一)查询
之前写的博客是对一个表进行查询。实际开发中经常会出现多表查询,下面就介绍任何操作。在学习的过程中一定要和前面的内容联系一起,会比较轻松。 另外应该有必要解释一下什么叫做一对一查询,就是主表的一个记录对应从表的一个记录;多对一就是主表的多条记录对应从表的一条记录
1.1 表的准备
下面的描述将根据两个简单的表,分别是user表和account表
同时要在Java工程中的domain文件夹内创建好这两个实体类。
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
// 还有各个属性的 get 和 set 和toString方法 这里为了简便就不放在这里了。
}
public class Account implements Serializable {
private Integer id;
private Integer uid;
private double money;
// 还有各个属性的 get 和 set 和toString方法 这里为了简便就不放在这里了。
}
1.2 需求分析
在这里我们要进行的多表联合查询的语句及结果是:
SELECT
account.*,
user.username,
user.address
FROM
account,
user
WHERE account.uid = user.id
1.3 方法一
分析上面图中的返回结果,按照之前的逻辑来解决的话,那就是用一个类来装返回的结果,这就是方式一 在domain中创建AccountUser类:
public class AccountUser extends Account{
private String username;
private String address;
@Override
public String toString() {
return super.toString() + " AccountUser{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
1.4 常规操作
1.4.1 在dao文件夹中创建Dao接口
public interface IAccountDao {
/**
* 查询所有账户,并且带有用户名称和地址信息
* @return
*/
List<AccountUser> findAllAccount();
}
1.4.2 在resource下的dao包中创建对应的配置文件
<!--查询所有同时包含用户名和地址信息-->
<select id="findAllAccount" resultType="AccountUser">
SELECT account.*,user.username,user.address FROM account,user WHERE account.uid = user.id
</select>
- 注意,这里不需要再去SqlMapConfig.xml文件中创建对应mapper,因为已经在SqlMapConfig.xml的
<configuration> </configuration>
中加入了:
<!-- 配置映射文件的位置-->
<mappers>
<package name="com.zhouman.dao"/>
</mappers>
可以直接写:resultType="AccountUser"
是因为在SqlMapConfig.xml的<configuration> </configuration>
中加入了:
<typeAliases>
<package name="com.zhouman.domain"/>
</typeAliases>
1.4.3 在test包下创建测试类进行测试:
public class AccountTest {
private InputStream inputStream;
private SqlSession sqlSession;
private IAccountDao accountDao;
@Before
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
inputStream = Resource.class.getResourceAsStream("/SqlMapConfig.xml");
//2.获取SqlSessionFactory对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.通过SqlSession生产dao的代理对象
accountDao = sqlSession.getMapper(IAccountDao.class);
}
@After
public void destroy() throws Exception {
//提交事务
sqlSession.commit();
inputStream.close();
sqlSession.close();
}
/**
* 查询所有账户,同时包含用户名称和地址
* @throws Exception
*/
@Test
public void testFindAllAccountUser() {
//5.执行方法
List<AccountUser> accountUsers = accountDao.findAllAccount();
for (Account accountUser : accountUsers){
System.out.println(accountUser);
}
}
1.5 方法二
下面总结一下方法一:该方法的逻辑就是用一个类来装结果。但是实际工程运用当中,这种方式用的不多。
更多的会去使用方法二:使用resultMap,定义专门的resultMap用于映射一对一查询结果
1.5.1 修改 Account类
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
// 还有各个属性的 get 和 set 和toString方法 这里为了简便就不放在这里了。
}
1.5.2 添加AccountDao接口中的方法
public interface IAccountDao {
/**
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/
List<Account> findAll();
}
1.5.3 重新定义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.zhouman.dao.IAccountDao">
<!-- 定义封装account 和user 的 accountUserMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="uid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射:配置封装user的内容 -->
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="ser" column="sex"></result>
<result property="birthday" column="birthday"></result>
</association>
</resultMap>
<!--查询所有-->
<select id="findAll" resultMap="accountUserMap">
<!--select * from account-->
select a.*,u.username,u.address from account as a, user as u where u.id = a.uid
</select>
</mapper>
1.5.4 在 AccountTest 类中加入测试方法
@Test
public void testFindAll() {
List<Account> accounts = accountDao.findAll();
for(Account au : accounts) {
System.out.println(au);
System.out.println(au.getUser());
}
}
总结
实际运用中方式二用得更多,其实方式二相较而言也更加方便,需要改动的点不多。
2 一对多查询
一对多查询就是,主表的一条记录对应从表的多条记录 查询出来的效果大致如下图:
而Mybatis是可以将其封装在一起的
这次用的方法是上面所述的方法二,即resultMap
2.1 User 类加入 List<Account>
......
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
......
2.2 用户持久层 Dao 接口中加入查询方法
/**
* 查询所有用户,同时获取出每个用户下的所有账户信息
* @return
*/
List<User> findAll();
值得注意的是这里返回的是 List 集合
2.3用户持久层 Dao 映射文件配置
<!-- 定义User的resultMap -->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!--查询所有,同时获取到用户下所有账户的信息-->
<select id="findAll" resultMap="userAccountMap">
select * from user;
</select>
这里的话,和前面一对一多表查询的差别在于,这里用的是<collection></collection>
标签
2.4 测试方法
@Test
public void testFindAll() {
//6.执行操作
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println("-------每个用户的内容---------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}