跳到主要内容

15、MyBatis速成 - 返回结果封装

前面介绍的内容查询结果基本都是返回一个数据,然后将数据对应某一个对象。本篇探索一下多种不同类型的返回结果,mybatis是如何封装的。

1.返回list

创建Employee对象

package org.mybatis.returntype;

import org.apache.ibatis.type.Alias;

@Alias("empp")
public class Employee {
   
     
    private Integer id;
    private String lastName;
    private String email;
    private String gender;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    @Override
    public String toString() {
        return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email
                + ", gender=" + gender + "]";
    }
}

创建接口类

package org.mybatis.returntype;

import java.util.List;

public interface EmployeeMapper {
   
     

    public List<Employee> getEmpByLastName(String lastName);

}

创建映射配置文件,使用like查询返回一个list集合,list集合中存放Employee对象。返回值类型仍然使用对象,而不是list

<?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="org.mybatis.returntype.EmployeeMapper">

    <select id="getEmpByLastName" resultType="empp">
        select id,last_name,email,gender from mybatis_employee where last_name like{lastName}
    </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 resource="db.properties"></properties>

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
        <!-- 为包下的所有类起别名,默认为类名大小写(不区分大小写) -->
        <package name="org.mybatis.returntype"/>
    </typeAliases>

    <!-- 默认development是开发环境,如果改成test则表示使用测试环境 -->
    <environments default="dev_mysql">
        <environment id="dev_mysql">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${mysql.driver}" />
                <property name="url" value="${mysql.url}" />
                <property name="username" value="${mysql.username}" />
                <property name="password" value="${mysql.password}" />
            </dataSource>
        </environment>

        <environment id="test_mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${mysql.drivertest}" />
                <property name="url" value="${mysql.urltest}" />
                <property name="username" value="${mysql.usernametest}" />
                <property name="password" value="${mysql.passwordtest}" />
            </dataSource>
        </environment>

    </environments>

    <mappers>
        <mapper resource="mapper/returntypemapper.xml"/>
    </mappers>

</configuration>

创建测试类

package org.mybatis.returntype;

import java.io.IOException;
import java.io.InputStream;
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 org.junit.Test;

/**
 * 使用接口式編程
 */
public class MybatisTest {
   
     

    @Test
    public void testMybatis() {
        String resource = "mybatis-config-returntype.xml";//全局配置文件

        InputStream inputStream = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession();

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            List<Employee> emp = mapper.getEmpByLastName("%an%");
            System.out.println(emp);

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

返回结果如下:

DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@e320068]
DEBUG - ==> Preparing: select id,last_name,email,gender from mybatis_employee where last_name like ?
DEBUG - ==> Parameters: %an%(String)
[Employee [id=3, lastName=panpan, email=tang_greatman@sohu.com, gender=1], Employee [id=4, lastName=huanhuan, email=tang_greatman@sina.com, gender=2], Employee [id=5, lastName=huanhuan, email=tang_greatman@sina.com, gender=2], Employee [id=6, lastName=huanan, email=tang_man@sina.com, gender=2], Employee [id=7, lastName=hussanan, email=tang_@qq.com, gender=2], Employee [id=8, lastName=hussanan, email=tang_@qq.com, gender=2]]
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@e320068]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@e320068]
DEBUG - Returned connection 238157928 to pool.

结果返回为一个集合。

2.返回map

a)返回一条记录的map
创建接口方法

public Map<String,Object> getEmpById(Integer id);

创建sql,这里map类型是一个Map的缩写

<select id="getEmpById" resultType="map">
        select * from mybatis_employee where id ={id}
    </select>

创建测试

package org.mybatis.returntype;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

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 org.junit.Test;

/**
 * 使用接口式編程
 */
public class MybatisTest {
   
     

    @Test
    public void testMybatis() {
        String resource = "mybatis-config-returntype.xml";//全局配置文件

        InputStream inputStream = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession();

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//          List<Employee> emp = mapper.getEmpByLastName("%an%");
//          System.out.println(emp);

            Map<String, Object> empmap = mapper.getEmpById(2);
            System.out.println(empmap);

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

返回结果:

DEBUG - ==> Preparing: select * from mybatis_employee where id = ?
DEBUG - ==> Parameters: 2(Integer)
{gender=2, last_name=lisi, id=2, email=tang_greatman@qq.com}
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1f57539]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1f57539]
DEBUG - Returned connection 32863545 to pool.

返回结果已经将对象封装为一个map对象。

b)返回多条记录封装到一个map中
创建接口方法
指定id作为map中的键,javabean作为值

/**
 * @param lastName
 * @return 键是某个属性,值是javabean
 */
@MapKey("id")
public Map<Integer,Employee> getEmpByLastNameLike(String lastName);

创建sql语句,指定返回值类型为Employee对象

<select id="getEmpByLastNameLike" resultType="empp">
    select * from mybatis_employee where last_name like{lastName}
</select>

创建测试类

package org.mybatis.returntype;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

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 org.junit.Test;

/**
 * 使用接口式編程
 */
public class MybatisTest {
   
     

    @Test
    public void testMybatis() {
        String resource = "mybatis-config-returntype.xml";//全局配置文件

        InputStream inputStream = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession();

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//          List<Employee> emp = mapper.getEmpByLastName("%an%");
//          System.out.println(emp);

//          Map<String, Object> empmap = mapper.getEmpById(2);
//          System.out.println(empmap);

            Map<Integer, Employee> mapbean = mapper.getEmpByLastNameLike("%an%");
            System.out.println(mapbean);

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

返回结果:

DEBUG - ==> Preparing: select * from mybatis_employee where last_name like ?
DEBUG - ==> Parameters: %an%(String)
{3=Employee [id=3, lastName=panpan, email=tang_greatman@sohu.com, gender=1],
4=Employee [id=4, lastName=huanhuan, email=tang_greatman@sina.com, gender=2],
5=Employee [id=5, lastName=huanhuan, email=tang_greatman@sina.com, gender=2],
7=Employee [id=7, lastName=hussanan, email=tang_@qq.com, gender=2], 8=Employee [id=8, lastName=hussanan, email=tang_@qq.com, gender=2]}
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4493d195]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4493d195]
DEBUG - Returned connection 1150538133 to pool.
返回结果键为数据记录id,值为Employee对象。

3.resultmap

上面两种返回,都是使用resulttype对查询的结果进行封装,且封装的都是单个对象。而实际的生产环境中有很多的关联查询,使用resulttype进行封装显然已经不能满足需求。mybatis提供了一种自定义封装方式resulmap,结合示例做一个介绍:

1)一个employee对应一个department

创建Employee和Department:

package org.mybatis.resultmap;

/**
 * ALTER TABLE mybatis_employee ADD COLUMN dept_id INT(11) COMMENT '部门id';
 * ALTER TABLE mybatis_employee ADD CONSTRAINT mybatis_dept_emp FOREIGN KEY (dept_id) REFERENCES mybatis_department (id);
 */
public class Employee {
   
     
    private Integer id;
    private String lastName;
    private String email;
    private String gender;
    private Department department;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    @Override
    public String toString() {
        return "Employee [id=" + id + ", lastName=" + lastName + ", email="
                + email + ", gender=" + gender + ", department=" + department
                + "]";
    }

}
package org.mybatis.resultmap;
public class Department {
   
     

    private Integer id;
    private String deptName;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    public String toString() {
        return "Department [id=" + id + ", deptName=" + deptName + "]";
    }
}

创建接口:

package org.mybatis.resultmap;

public interface EmployeeMapper {
   
     

    public Employee getEmpById(Integer id);

}

创建表和外键:

CREATE TABLE mybatis_employee (
  id int(11) NOT NULL AUTO_INCREMENT,
  last_name varchar(255) DEFAULT NULL,
  email varchar(255) DEFAULT NULL,
  gender varchar(255) DEFAULT NULL,
  dept_id int(11) DEFAULT NULL COMMENT '部门id',
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

CREATE TABLE mybatis_department (
  id int(11) NOT NULL,
  deptName varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--创建外键关联
ALTER TABLE mybatis_employee ADD CONSTRAINT mybatis_dept_emp FOREIGN KEY (dept_id) REFERENCES mybatis_department (id);

创建映射配置文件:
创建<resultMap type="org.mybatis.resultmap.Employee" id="memp"> 标签,设置id=memp,返回值类型为Employee对象,将<select id="getEmpById" resultMap="memp"> 查询结果通过resultMap标签和实际javabean属性一一对应。此时查询结果就会按照resultMap中设置的对应关系将查询结果设置到Employee对象中。有了这种自定义方式,之前的驼峰命名配置就可以去除掉。

<?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="org.mybatis.resultmap.EmployeeMapper">

    <!--这里department是按照属性传递进行书写-->
    <resultMap type="org.mybatis.resultmap.Employee" id="memp">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <result column="did" property="department.id"/>
        <result column="deptName" property="department.deptName"/>
    </resultMap>

    <select id="getEmpById" resultMap="memp">
        select me.id,me.last_name,me.email,me.gender,me.dept_id d_id,md.id did,md.deptName from mybatis_employee me,mybatis_department md where me.dept_id = md.id and me.id ={id}
    </select>
</mapper>

也可以将resultMap通过association进行关联,代码如下:

<resultMap type="org.mybatis.resultmap.Employee" id="memp2">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <association property="department" javaType="org.mybatis.resultmap.Department">
            <id column="did" property="id"/>
            <result column="deptName" property="deptName"/>
        </association>
    </resultMap>

创建主配置文件:

<?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 resource="db.properties"></properties>

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
        <!-- 为包下的所有类起别名,默认为类名大小写(不区分大小写) -->
        <package name="org.mybatis.resultmap"/>
    </typeAliases>
    <!-- 默认development是开发环境,如果改成test则表示使用测试环境 -->
    <environments default="dev_mysql">
        <environment id="dev_mysql">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${mysql.driver}" />
                <property name="url" value="${mysql.url}" />
                <property name="username" value="${mysql.username}" />
                <property name="password" value="${mysql.password}" />
            </dataSource>
        </environment>

        <environment id="test_mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${mysql.drivertest}" />
                <property name="url" value="${mysql.urltest}" />
                <property name="username" value="${mysql.usernametest}" />
                <property name="password" value="${mysql.passwordtest}" />
            </dataSource>
        </environment>
    </environments> 
    <mappers>
        <mapper resource="mapper/resultmapmapper.xml"/>
    </mappers>

</configuration>

创建测试类:

package org.mybatis.resultmap;

import java.io.IOException;
import java.io.InputStream;

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 org.junit.Test;
/**
 * 使用接口式編程
 */
public class MybatisTest {
   
     

    @Test
    public void testMybatis() {
        String resource = "mybatis-config-resultmap.xml";//全局配置文件

        InputStream inputStream = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession();

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee emp = mapper.getEmpById(2);
            System.out.println(emp);

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

执行结果:

DEBUG - ==> Preparing: select me.id,me.last_name,me.email,me.gender,me.dept_id d_id,md.id did,md.deptName from mybatis_employee me,mybatis_department md where me.dept_id = md.id and me.id = ?
DEBUG - ==> Parameters: 2(Integer)
Employee [id=2, lastName=lisi, email=tang_greatman@qq.com, gender=2, department=Department [id=2, deptName=测试部]]
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6ee52dcd]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6ee52dcd]
DEBUG - Returned connection 1860513229 to pool.

联合查询数据已经设置到javabean中。

2)一个department对应多个employee
上面介绍的是在一个employee中对应一个department对象,如果查询某一个id的employee,那么返回的结果是1。如果在department中存在一个employee集合,那么查询某一个id的department,返回的就是一个employee集合,结果又该如何处理呢?

Employee类,接口,配置文件,映射文件保持不变。Department做相关调整

实体类变更为

添加Employee集合

package org.mybatis.resultmap;
import java.util.List;
public class Department {
   
     

    private Integer id;
    private String deptName;
    /**
     * 添加emp集合
     */
    private List<Employee> emps;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public List<Employee> getEmps() {
        return emps;
    }
    public void setEmps(List<Employee> emps) {
        this.emps = emps;
    }

    public String toString() {
        return "Department [id=" + id + ", deptName=" + deptName + "]";
    }
}

接口类变更为

添加查询方法

public Department getDeptWithEmpById(Integer id);

映射文件变更为
返回的Employee集合使用<collection> 标签进行接收,类型使用ofType="" 进行配置

<?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="org.mybatis.resultmap.DepartmentMapper">

    <select id="getDeptById" resultType="org.mybatis.resultmap.Department">
        select id,deptName from mybatis_department where id ={id}
    </select>

    <resultMap type="org.mybatis.resultmap.Department" id="mdept1">
        <id column="did" property="id"/>
        <result column="deptName" property="deptName"/>
        <!-- 一个department对应多个employee -->
        <collection property="emps" ofType="org.mybatis.resultmap.Employee">
            <id column="eid" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
        </collection>
    </resultMap>

    <select id="getDeptWithEmpById" resultMap="mdept1">
        SELECT
            md.id did,
            md.deptName deptName,
            me.id eid,
            me.last_name last_name,
            me.email email,
            me.gender gender
        FROM
            mybatis_department md
        LEFT JOIN mybatis_employee me ON md.id = me.dept_id
        WHERE
            md.id ={id}
    </select>
</mapper>

测试

package org.mybatis.resultmap;

import java.io.IOException;
import java.io.InputStream;

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 org.junit.Test;

/**
 * 使用接口式編程
 */
public class MybatisTest {
   
     

    @Test
    public void testMybatis() {
        String resource = "mybatis-config-resultmap.xml";//全局配置文件

        InputStream inputStream = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession();

            DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
            Department dept1 = mapper.getDeptWithEmpById(2);
            System.out.println(dept1);
            System.out.println(dept1.getEmps());

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

返回结果

DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@4cf4d528]
DEBUG - ==> Preparing: SELECT md.id did, md.deptName deptName, me.id eid, me.last_name last_name, me.email email, me.gender gender FROM mybatis_department md LEFT JOIN mybatis_employee me ON md.id = me.dept_id WHERE md.id = ?
DEBUG - ==> Parameters: 2(Integer)
Department [id=2, deptName=测试部]
[Employee [id=2, lastName=lisi, email=tang_greatman@qq.com, gender=2], Employee [id=5, lastName=huanhuan, email=tang_greatman@sina.com, gender=2], Employee [id=6, lastName=huanan, email=tang_man@sina.com, gender=2]]
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4cf4d528]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4cf4d528]
DEBUG - Returned connection 1291113768 to pool.

封装完毕