各种查询功能
查询一个实体类
新建一个SelectMapper接口
package com.mybatis.mapper;
import com.mybatis.entity.User;
import org.apache.ibatis.annotations.Param;
public interface SelectMapper {
User getUserById(@Param("id") int id);
}
新建对应的映射
<?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.mybatis.mapper.SelectMapper">
<select id="getUserById" resultType="User">
select * from t_user where id = #{id,jdbcType=INTEGER}
</select>
</mapper>
创建测试类TestSelectMapper
package com.kesteler.mybatisTest;
import com.mybatis.entity.User;
import com.mybatis.mapper.SelectMapper;
import com.mybatis.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class TestSelectMapper {
@Test
public void testGetUserById(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
User user = selectMapper.getUserById(2);
System.out.println(user);
sqlSession.close();
}
}
结果:
查询一个List集合
当查询的数据为多条时,不能使用实体类作为返回值,否则会抛出异常TooManyResultsException;
但是若查询的数据只有一条,可以使用实体类或集合作为返回值
添加方法:
List<User> getAllUser();
在SelectMapper.xml中添加语句
<select id="getAllUser" resultType="user">
select * from t_user
</select>
测试代码
@Test
public void testGetAllUser(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
List<User> list_user = selectMapper.getAllUser();
list_user.forEach(System.out::println);
sqlSession.close();
}
查询单个数据
单行单列数据,比如数量、平均数,或者某个具体条件查询的某个字段值
SelectMapper.java接口
int getCount();
SelectMapper.xml
<select id="getCount" resultType="java.lang.Integer">
select count(*) from t_user
</select>
测试
@Test
public void testGetCount(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
int count = selectMapper.getCount();
System.out.println("count = " + count);
sqlSession.close();
}
当把resultType中的内容替换成int,Integer,INT,integer等都可以成功
结论:
1.resultType后面的内容不区分大小写
2.resultType提前设置好了别名
MyBatis别名对应文档
Alias别名 | Mapped Type(Mapper接口返回类型) |
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
查询一条数据为map集合
查询的时候,不是字段名就对应实体类,而是起了别名,那么就需要map集合了。
SelectMapper.java
Map<String,Object> getUserByIdToMap(@Param("id")int id);
SelectMapper.xml
<select id="getUserByIdToMap" resultType="map">
select * from t_user where id = #{id}
</select>
测试代码
@Test
public void testGetUserByIdToMap(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
Map<String ,Object> map = selectMapper.getUserByIdToMap(2);
System.out.println(map);
sqlSession.close();
}
注意:
如果有字段为null那么map集合是不会放进去值的。
查询多条数据为map集合
方式一:
将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取。
SelectMapper.java
List<Map<String,Object>> getAllUserToMap1();
SelectMapper.xml
<select id="getAllUserToMap1" resultType="map">
select * from t_user
</select>
测试代码
@Test
public void testGetAllUserToMap1(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
List<Map<String,Object>> list_map = selectMapper.getAllUserToMap1();
System.out.println(list_map);
sqlSession.close();
}
方式二:
将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,并且最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的map集合。
SelectMapper.java
@MapKey("id")
Map<String,Object> getAllUserToMap2();
SelectMapper.xml
<select id="getAllUserToMap2" resultType="map">
select * from t_user
</select>
测试代码
@Test
public void testGetAllUserToMap2(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
Map<String,Object> map = selectMapper.getAllUserToMap2();
System.out.println(map);
Set<Map.Entry<String,Object>> entries = map.entrySet();
for (Map.Entry<String, Object> entry : entries) {
System.out.println(entry);
}
sqlSession.close();
}
特殊SQL的执行
防止出现sql注入,一般都使用#{}占位符的方式,但是如下几个特殊的sql一般使用${}的形式。
新建SpecialSqlMapper.java
新建映射SpecialSqlMapper.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.mybatis.mapper.SpecialSqlMapper">
<select id="getUserByLike" resultType="User">
select * from t_user where username like '%#{un}%'
</select>
</mapper>
新建测试程序TestSpecialSqlMapper.java
模糊查询
SpecialSqlMapper.java
List<User> getUserByLike(@Param("un") String username);
SpecialSqlMapper.xml
<select id="getUserByLike" resultType="User">
select * from t_user where username like '%#{un}%'
</select>
测试程序
@Test
public void testGetUserByLike(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SpecialSqlMapper specialSqlMapper = sqlSession.getMapper(SpecialSqlMapper.class);
List<User> list_user = specialSqlMapper.getUserByLike("test");
for (User user : list_user) {
System.out.println(user);
}
sqlSession.close();
}
还原一下报错原因
@Test
public void testJdbc() {
try {
//Class.forName("");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybtistest", "root",
"000000");
String sql = "select * from t_user where username like '%?%'";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
int i = 1;
preparedStatement.setString(1, "a");
} catch (Exception e) {
e.printStackTrace();
}
}
编译报错,没有找到参数,说明?不代表占位符了,问号就是问号
修改映射文件SpecialSqlMapper.xml的sql
<select id="getUserByLike" resultType="User">
select * from t_user where username like '%${un}%'
</select>
测试结果:
或者使用concat拼接函数
concat('%', #{un}, '%')
或者
like "%"#{un}"%"
批量删除
SpecialSqlMapper.java
int deleteMoreUser(@Param("ids") String ids);
SpecialSqlMapper.xml
<delete id="deleteMoreUser">
delete from t_user where id in (${ids})
</delete>
测试程序
@Test
public void testDeleteMoreUser(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SpecialSqlMapper specialSqlMapper = sqlSession.getMapper(SpecialSqlMapper.class);
int i = specialSqlMapper.deleteMoreUser("1,2");
System.out.println("删除了:" + i);
sqlSession.close();
}
不能使用#{},字符串参数时,#{}会自动两边加单引号导致报错。
动态设置表名
SpecialSqlMapper.java
List<User> getUserByTableName(@Param("tablename") String tablename);
SpecialSqlMapper.xml
<select id="getUserByTableName" resultType="User">
select * from ${tablename}
</select>
测试程序
@Test
public void testGetUserByTableName(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SpecialSqlMapper specialSqlMapper = sqlSession.getMapper(SpecialSqlMapper.class);
List<User> list_user = specialSqlMapper.getUserByTableName("t_user");
for (User user : list_user) {
System.out.println(user);
}
sqlSession.close();
}
不能用#{},因为会默认添加单引号
添加功能获取自增的主键
SpecialSqlMapper.java
int insertUser(User user);
SpecialSqlMapper.xml
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user values (#{id},#{username},#{password},#{age},#{gender},#{email})
</insert>
useGeneratedKeys:设置使用自增的主键。
keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中。
测试程序
@Test
public void testInsertUser(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
SpecialSqlMapper specialSqlMapper = sqlSession.getMapper(SpecialSqlMapper.class);
User user = new User();
user.setUsername("test11");
user.setPassword("000");
user.setAge(10);
user.setGender("女");
user.setEmail("12345@123.com");
System.out.println("插入前:" + user);
specialSqlMapper.insertUser(user);
System.out.println("插入后:" + user);
sqlSession.close();
}
自定义映射resultMap
resultMap处理字段和属性的映射关系
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射
准备工作:
新建两张表
CREATE TABLE `t_emp` (
`emp_id` INT(11) NOT NULL AUTO_INCREMENT,
`emp_name` VARCHAR(20) DEFAULT NULL,
`age` INT(11) DEFAULT NULL,
`gender` CHAR(1) DEFAULT NULL,
`dept_id` INT(11) DEFAULT NULL,
PRIMARY KEY (`emp_id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
CREATE TABLE `t_dept` (
`dept_id` INT(11) NOT NULL AUTO_INCREMENT,
`dept_name` VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (`dept_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
编写两个表的实体类:
package com.mybatis.entity;
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String gender;
private Integer deptId;
public Emp() {
}
public Emp(Integer empId, String empName, Integer age, String gender, Integer deptId) {
this.empId = empId;
this.empName = empName;
this.age = age;
this.gender = gender;
this.deptId = deptId;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", deptId=" + deptId +
'}';
}
}
package com.mybatis.entity;
public class Dept {
private Integer deptId;
private String deptName;
public Dept() {
}
public Dept(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Override
public String toString() {
return "Dept{" +
"deptId=" + deptId +
", deptName='" + deptName + '\'' +
'}';
}
}
创建对应的接口和配置文件EmpMapper.java,DeptMapper.java,EmpMapper.xml,DeptMapper.xml,TestResultMap.java
在EmpMapper.java
Emp getEmpByEmpId(@Param("empId") Integer empId);
EmpMapper.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.mybatis.mapper.EmpMapper">
<select id="getEmpByEmpId" parameterType="java.lang.Integer" resultType="Emp">
select * from t_emp where emp_id = #{empId}
</select>
</mapper>
测试程序
@Test
public void testGetEmpByEmpId(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpByEmpId(1);
System.out.println(emp);
sqlSession.close();
}
结果无内容,是因为实体类的属性跟数据库表的字段不一致
解决方法一:
字段起别名,是属性名
修改EmpMapper.xml
<select id="getEmpByEmpId" parameterType="java.lang.Integer" resultType="Emp">
select emp_id empId,emp_name empName,age,gender,dept_id deptId from t_emp where emp_id = #{empId}
</select>
结果:
方法二:设置一个全局配置信息
mybatis-config.xml中添加
<!-- mapUnderscoreToCamelCase将下划线映射为驼峰 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
结果
注意:实体类中属性的命名必须是驼峰规则
方法三:用自定义映射resultMap实现
更改EmpMapper.xml文件,选择使用resultMap的方式
resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名
EmpMapper.xml
<resultMap id="empResultMap" type="Emp">
<!-- id 设置数据库主键和属性名的映射关系 -->
<id column="emp_id" property="empId"></id>
<!-- result 设置数据库非主键字段和属性名的映射关系 -->
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<result column="dept_id" property="deptId"></result>
</resultMap>
<select id="getEmpByEmpId" parameterType="java.lang.Integer" resultMap="empResultMap">
select * from t_emp where emp_id = #{empId}
</select>
结果
总结:
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。
此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
a>.可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
b>.可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为userName
多对一映射处理
针对Emp实体类进行修改,分析deptId字段,一个员工只有一个部门是1对1,那么是用对象返回。
Emp.java:
private Dept dept;
public Dept getDept(){
return dept;
}
public void setDept(Dept dept){
this.dept = dept;
}
EmpMapper.java
Emp getEmpAndDeptByEmpid(@Param("empId") Integer empId);
EmpMapper.xml
<select id="getEmpAndDeptByEmpid" parameterType="int" resultType="Emp">
select a.*,b.dept_name from t_emp a left join t_dept b on a.dept_id = b.dept_id where emp_id = #{empId}
</select>
测试程序
@Test
public void testGetEmpAndDeptByEmpid(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByEmpid(1);
System.out.println(emp);
sqlSession.close();
}
未获取到dept
方法一:级联方式处理映射关系
在EmpMapper.xml中添加sql
<resultMap id="empAndDeptResultMap" type="Emp">
<!-- id 设置数据库主键和属性名的映射关系 -->
<id column="emp_id" property="empId"></id>
<!-- result 设置数据库非主键字段和属性名的映射关系 -->
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<result column="dept_id" property="dept.deptId"></result>
<result column="dept_name" property="dept.deptName"></result>
</resultMap>
<select id="getEmpAndDeptByEmpid" parameterType="int" resultMap="empAndDeptResultMap">
select a.*,b.dept_name from t_emp a left join t_dept b on a.dept_id = b.dept_id where emp_id = #{empId}
</select>
测试
方法二:使用association处理映射关系
在EmpMapper.xml中添加sql
<resultMap id="empAndDeptResultMap2" type="Emp">
<!-- id 设置数据库主键和属性名的映射关系 -->
<id column="emp_id" property="empId"></id>
<!-- result 设置数据库非主键字段和属性名的映射关系 -->
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!-- association 处理多对一的映射关系,也可以处理一对一,主要处理实体类的属性
property 设置实体类中dept对象的映射关系
javaType 设置实体类dept的类型Dept
-->
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
<select id="getEmpAndDeptByEmpid" parameterType="int" resultMap="empAndDeptResultMap2">
select a.*,b.dept_name from t_emp a left join t_dept b on a.dept_id = b.dept_id where emp_id = #{empId}
</select>
结果:
方法三:分步查询
(1)查询员工信息
EmpMapper.java
Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);
EmpMapper.xml
<!-- 方法3:分步查询-->
<resultMap id="getEmpAndDeptByStepOnResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!-- association 处理多对一的映射关系,也可以处理一对一,主要处理实体类的属性
property 设置实体类中dept对象的映射关系
select 设置分布查询中dept对象的属性从另外哪个sql获取,这里取值是mapper接口中方法的全类名
column 多表查询中外键字段的字段名
-->
<association property="dept" select="com.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="dept_id">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
<select id="getEmpAndDeptByStepOne" resultMap="getEmpAndDeptByStepOnResultMap">
select * from t_emp where emp_id = #{empId}
</select>
(2)根据员工所对应的部门id查询部门信息
DeptMapper.java
Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);
DeptMapper.xml
<select id="getEmpAndDeptByStepTwo" resultType="Dept">
select * from t_dept where dept_id = #{deptId}
</select>
测试代码
@Test
public void testGetEmpAndDeptByStepOne(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByStepOne(1);
System.out.println(emp);
sqlSession.close();
}
(3)分布查询的优势
延迟加载(懒加载)
如果当前只查询员工信息,而不需要部门信息,那么就不会查询部门信息,即:不会进行第二步的查询,可以减少内存的消耗。
如果要开启延迟加载,需要开启配置信息
查看官方文档
lazyLoadingEnabled:延迟加载的全局开关。当设置为true时,所有关联对象都会延迟加载。
aggressiveLazyLoading:当设置为true时,任何方法的调用都会加载该对象的所有属性。设置成false的时候每个属性会按需加载。比如,如果设置成true那么无论查询什么信息,2步查询都会查,如果设置成false配合lazyLoadingEnabled设置true可以实现按需加载,即如果查询员工姓名,则不会执行部门查询的sql语句。
在mybatis-config.xml增加
<!-- 开启延迟加载(懒加载) -->
<setting name="lazyLoadingEnabled" value="true"/>
设置后,如果只读取emp中的属性,则不会执行steptwo的方法sql
@Test
public void testGetEmpAndDeptByStepOne(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByStepOne(1);
//System.out.println(emp);
System.out.println(emp.getEmpName());
sqlSession.close();
}
如果查询到dept表的属性,则会执行两步
@Test
public void testGetEmpAndDeptByStepOne(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.getEmpAndDeptByStepOne(1);
//System.out.println(emp);
//System.out.println(emp.getEmpName());
System.out.println(emp.getDept().getDeptName());
sqlSession.close();
}
设置另外一个参数aggressiveLazyLoading,因为默认是false可以省略
<!--aggressiveLazyLoading 设置false按需加载 -->
<!--aggressiveLazyLoading 设置true全部加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
注意,这样配置的延迟加载是全局变量,MyBatis中所有的分布查询都会遵循设置,那么如果某个Mapper查询不想遵从的话,可以association中的fetchType
修改EmpMapper.xml
<resultMap id="getEmpAndDeptByStepOnResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!-- association 处理多对一的映射关系,也可以处理一对一,主要处理实体类的属性
property 设置实体类中dept对象的映射关系
select 设置分布查询中dept对象的属性从另外哪个sql获取,这里取值是mapper接口中方法的全类名
column 多表查询中外键字段的字段名
fetchType lazy延迟加载 eager立即加载
-->
<association property="dept" select="com.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="dept_id" fetchType="eager">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
继续测试取emp中的属性
全部执行,延迟加载失效
一对多映射处理
Dept.java中添加属性
private List<Emp> emps;
package com.mybatis.entity;
import java.util.List;
public class Dept {
private Integer deptId;
private String deptName;
private List<Emp> emps;
public Dept() {
}
public Dept(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public List<Emp> getEmps(){
return emps;
}
public void setEmps(List<Emp> emps){
this.emps = emps;
}
@Override
public String toString() {
return "Dept{" +
"deptId=" + deptId +
", deptName='" + deptName + '\'' +
",emps=" + emps +
'}';
}
}
方法一:collection
DeptMapper.java
Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);
DeptMapper.xml
<resultMap id="getDeptAndEmpByDeptIdResultMap" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<!--collection处理一(多)对多的映射关系 集合类型 -->
<!-- ofType设置集合中的类型,比如这里Dept实体类中有属性emp,那么该类型来自于实体类Emp,则ofTyoe是Emp -->
<collection property="emps" ofType="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<result column="dept_id" property="deptId"></result>
</collection>
</resultMap>
<select id="getDeptAndEmpByDeptId" resultMap="getDeptAndEmpByDeptIdResultMap">
select * from t_dept a left join t_emp b on a.dept_id = b.dept_id where a.dept_id = #{deptId}
</select>
测试程序
@Test
public void testGetDeptAndEmpByDeptId(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
Dept dept = deptMapper.getDeptAndEmpByDeptId(1);
System.out.println(dept);
sqlSession.close();
}
方法二:分步查询
(1)查询部门信息
DeptMapper.java
Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);
DeptMapper.xml
<resultMap id="getDeptAndEmpByStepOneResultMap" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<!--collection处理一(多)对多的映射关系 集合类型 -->
<!-- ofType设置集合中的类型,比如这里Dept实体类中有属性emp,那么该类型来自于实体类Emp,则ofTyoe是Emp -->
<collection property="emps" select="com.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo" fetchType="lazy"
column="dept_id">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
</collection>
</resultMap>
<select id="getDeptAndEmpByStepOne" resultMap="getDeptAndEmpByStepOneResultMap">
select * from t_dept where dept_id = #{deptId}
</select>
(2)根据部门id查询部门中的所有员工
EmpMapper.java
List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);
EmpMapper.xml
<select id="getDeptAndEmpByStepTwo" resultType="Emp">
select * from t_emp where dept_id = #{deptId}
</select>
测试程序
@Test
public void testGetDeptAndEmpByStepOne(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
Dept dept = deptMapper.getDeptAndEmpByStepOne(1);
System.out.println(dept);
sqlSession.close();
}
测试延迟加载
@Test
public void testGetDeptAndEmpByStepOne(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
Dept dept = deptMapper.getDeptAndEmpByStepOne(1);
//System.out.println(dept);
System.out.println(dept.getDeptName());
sqlSession.close();
}
分步查询总结:
分步查询的优点:可以实现延迟加载
但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType=“lazy(延迟加载)|eager(立即加载)”
其他
数据库表:
t_user:
t_emp:
t_dept:
分步查询继续扩展
继上面一对多查询,每个Emp中还有个Dept目前为null,可以展示出来
EmpMapper.xml
<resultMap id="getDeptAndEmpByStepTwoResultMap" type="Emp">
<result column="dept_id" property="deptId"></result>
<association property="dept" select="com.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="dept_id" fetchType="lazy">
</association>
</resultMap>
<select id="getDeptAndEmpByStepTwo" resultMap="getDeptAndEmpByStepTwoResultMap">
select * from t_emp where dept_id = #{deptId}
</select>
发现dept不再是null了
测试延迟
上面resultMap里和association没有添加<id>和<result>的列和属性的映射是因为mybatis-config.xml全局配置了
<!-- mapUnderscoreToCamelCase将下划线映射为驼峰 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
2763

被折叠的 条评论
为什么被折叠?



