三、Mybatis如何返回结果集 方式一利用resultType结果集返回List集合
Dao层接口UserMapper增加findAll方法
public List<User> findAll();
映射文件UserMapper.xml中增加
<select id="findAll" resultType="com.zssj.domain.User">
select * from user
</select>
测试方法如下
@Test
public void test1() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> userList = userMapper.findAll();
for (User user : userList) {
System.out.println(user);
}
//5. 释放资源
session.close();
in.close();
}
在测试方法中userMapper调用findAll方法,查询出数据库中的所有数据。
可以看到Dao层的findAll方法的返回值是List集合,那么在UserMapper.xml对应的select标签使用结果集元素resultType时,将其值设为User类的全限定类名即可,那么查询出的所有数据都会被封装到该集合中。
方式二利用resultType结果集返回Map集合
Dao层接口UserMapper增加selectUsersByMap方法
@MapKey("id") public Map<String, User> selectUsersByMap();
映射文件UserMapper.xml中增加
select * from user 测试方法如下 @Test
public void test21() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
Map map = userMapper.selectUsersByMap();
//6. 释放资源
session.close();
in.close();
}
测试结果如下
{1=User{id=1, username='liuxiang', password='hello789', birthday=null},
2=User{id=2, username='lisi', password='hello123', birthday=null},
3=User{id=3, username='wangwu', password='hello123', birthday=null},
4=User{id=4, username='zhaoyun', password='hello123', birthday=null},
5=User{id=5, username='machao', password='hello123', birthday=null}}
通过结果可以知道,返回的结果集Map集合中key是每个User对象的id值,value是User对象。
当然key的值可以通过Dao层接口UserMapper对应方法的 @MapKey("")注解进行自定义,选取对象中的某个字段作为key就将这个字段的属性名放入注解即可。
值得一提的是select标签中的resultType元素仍然是User实体类的全限定类名。
方式三利用resultMap完成基本属性值封装
上述介绍了使用resultType将数据库中的结果自动封装到Java实体对象中,但是有些时候这种自动封装不能满足很多现实场景的需要。
比如数据库字段和Java实体类中的字段对应不上,因此值也就封装不起来,比如数据库的字段是user_name,而Java实体类中的属性名是username。
这个时候就需要借助resultMap,具体代码示例如下。
Dao层接口UserMapper增加selectUserByResultMap方法
public User selectUserByResultMap(Integer id);
映射文件UserMapper.xml中增加
<resultMap id="userResult" type="com.zssj.domain.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<resultcolumn="password" property="password"/>
<resultcolumn="mail_code" property="mailCode"/>
</resultMap>
<select id="selectUserByResultMap" resultMap="userResult">
select * from user where id = #{id}
</select>
测试方法如下
@Test
public void test22() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.selectUserByResultMap(1);
System.out.println(user);
//6. 释放资源
session.close();
in.close();
}
可以发现在UserMapper.xml对应的resultMap标签中id(一般设置主键字段)及result对应的是数据库查询出的字段名,而property对应的是java实体对象中的属性名称。
在上述完成了一一对应后,将对应规则赋给select标签的resultMap即可。
方式四resultMap完成一对一封装
所谓高级映射就是在java实体类中包含另一个实体类,在这种情况下myabtis是如何借助resultMap完成结果集封装的呢?
为了介绍此种情况,需要增加新的实体类Department。
public class Department {
private Integer id;
private String departmentName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
@Override
public String toString() {
return "Department{" +
"id=" + id +
", departmentName='" + departmentName + '\'' +
'}';
}
}
并且将该实体类也作为User类的属性元素即private Department department。
public class User {
private int id;
private String username;
private String password;
private Date birthday;
private String mailCode;
private Department department;
public User() {
}
public User( String username, String password) {
this.username = username;
this.password = password;
}
public User( int id,String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public User( int id,String username, String password, Date birthday,String mailCode) {
this.id = id;
this.username = username;
this.password = password;
this.birthday = birthday;
this.mailCode = mailCode;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public String getMailCode() {
return mailCode;
}
public void setMailCode(String mailCode) {
this.mailCode = mailCode;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday=" + birthday +
", mailCode='" + mailCode + '\'' +
", department=" + department +
'}';
}
}
如上所示,Department类型也作为User类的属性元素,这个时候通过下述示例代码介绍封装方法。
Dao层接口UserMapper增加getUserAndDept方法
public User getUserAndDept(Integer id); 映射文件UserMapper.xml中增加
<resultMap id="userResult2" type="com.zssj.domain.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<result column="mail_code" property="mailCode"/>
<result column="did" property="department.id"/>
<result column="dept_name" property="department.departmentName"/>
</resultMap>
<select id="getUserAndDept" resultMap="userResult2">
select u.id id, u.username username, u.password password,
u.birthday birthday,u.mail_code mail_code,u.dept_id dept_id,
d.id did, d.dept_name dept_name
from user u inner join tbl_dept d on u.dept_id = d.id where u.id = #{id}
</select>
在上述代码的select标签里依然用resultMap指定封装结果集的方式。
由于返回结果集是User类型的,而在User类型中有个引用数据类型Department,我们发现可以采用department.id、department.departmentName这种级联的方式将数据库中对应的字段值赋给Department的属性。
测试方法如下
@Test
public void test23() throws IOException {
//1. 读取核心配置文件SqlMapConfig.xml
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3. 使用工厂生产一个SqlSession对象
SqlSession session = factory.openSession();
//4. 使用SqlSession创建Dao接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.getUserAndDept(16);
System.out.println(user);
//6. 释放资源
session.close();
in.close();
}
在测试方法中调用getUserAndDept方法并传入参数员工的id值,根据此id查询员工信息和部门信息。
除了上述级联的方式外,还可以采用子标签association来完成这一封装。
那么只要将映射文件UserMapper.xml中对应的resultMap标签改为
<resultMap id="userResult3" type="com.zssj.domain.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<result column="mail_code" property="mailCode"/>
<association property="department" javaType="com.zssj.domain.Department">
<result column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
</association>
</resultMap>
我们发现将Department类型的属性值放入association标签中,并且与数据库字段值一一对应即可。
当然association子标签中javaType类型是Department类型。
方式五一对多查询
所谓一对多查询就是在一个实体对象中包含集合属性,假设在部门实体类中加入属性private List userList,即模拟一个部门中可以有很多员工。
这样可以满足需求在查询部门时将其所有员工悉数封装到属性userList中,那么具体在封装过程中,mybatis框架是如何实现的呢?答案还是使用resultMap。
Dao层接口DepartmentMapper增加方法getDeptByIdPlus
public Department getDeptByIdPlus(Integer id); 与其对应的DepartmentMapper.xml中的select标签为
<resultMap id="myDept" type="com.zssj.domain.Department">
<id column="did" property="id"/>
<result column="departName" property="departmentName"/>
<collection property="userList" ofType="com.zssj.domain.User">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<result column="mail_code" property="mailCode"/>
</collection>
</resultMap>
<select id="getDeptByIdPlus" resultMap="myDept">
select d.id did, d.dept_name departName, u.id uid, u.username username,
u.password password, u.birthday birthday, u.mail_code mail_code
from tbl_dept d left join user u on d.id = u.dept_id
where d.id = #{id}
</select>
在select标签中采用表连接的方式分别查出user表(用户表)和tbl_dept(部门表)的相关信息,业务需求则是通过部门id查出此部门的全部员工。
在resultMap中部门实体类中的id属性和departmentName属性可以实现简单的封装即可。
但是属性userList是集合类型,因此需要借助collection子标签,其中property对应的就是该属性名,而ofType对应的是集合中实体对象的全限定类名,这里对应的是User类。
在collection标签中完成User对象的属性值封装即可。