MyBatis(三)映射文件

"本文详细介绍了MyBatis中的映射文件配置,包括插入、更新、删除和查询操作,以及参数处理、结果集映射、缓存策略和主键生成方法。通过实例演示了如何使用resultMap、resultType、@Param和#{表达式}
摘要由CSDN通过智能技术生成

映射文件

映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义。

例如:
•cache –命名空间的二级缓存配置
•cache-ref – 其他命名空间缓存配置的引用。
•resultMap – 自定义结果集映射
•parameterMap – 已废弃!老式风格的参数映射
•sql –抽取可重用语句块。
•insert – 映射插入语句
•update – 映射更新语句
•delete – 映射删除语句
•select – 映射查询语句

数据库数据和实体对象准备,后面案例需要使用

CREATE DATABASE  IF NOT EXISTS `test` DEFAULT CHARACTER SET utf8 ;

USE `test`;

DROP TABLE IF EXISTS `tbl_dept`;

CREATE TABLE `tbl_dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `dept_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1006 DEFAULT CHARSET=utf8;


insert  into `tbl_dept`(`id`,`dept_name`) values 
(1001,'研发部'),
(1002,'生产部'),
(1003,'销售部'),
(1004,'客服部'),
(1005,'安保部');


DROP TABLE IF EXISTS `tbl_employee`;

CREATE TABLE `tbl_employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `last_name` varchar(255) DEFAULT NULL,
  `gender` char(1) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `d_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_emp_dept` (`d_id`),
  CONSTRAINT `fk_emp_dept` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

insert  into `tbl_employee`(`id`,`last_name`,`gender`,`email`,`d_id`) values 
(1,'张三','1','zhangsan@qq.com',1001),
(2,'tom','0','tom@qq.com',1002),
(3,'jerry','0','jerry@qq.com',1003),
(4,'jeck','1','jeck@qq.com',1004),
(5,'tom','1','tom@qq.com',1005),
(6,'lucy','0','lucy@qq.com',1001);

Employee

public class Employee {
    private Integer id;
    private String lastname;
    private String email;
    private String gender;
    private Dept dept;

    public Employee() {
    }

    public Employee(Integer id, String lastname, String email, String gender) {
        this.id = id;
        this.lastname = lastname;
        this.email = email;
        this.gender = gender;
    }

    public Employee(Integer id, String lastname, String email, String gender, Dept dept) {
        this.id = id;
        this.lastname = lastname;
        this.email = email;
        this.gender = gender;
        this.dept = dept;
    }


    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    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 + '\'' +
                ", dept=" + dept +
                '}';
    }
}

Dept

public class Dept {
    private Integer id;
    private String deptName;
    private List<Employee> emps;

    public List<Employee> getEmps() {
        return emps;
    }

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

    public Dept() {
    }

    public Dept(Integer id, String deptName) {
        this.id = id;
        this.deptName = 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;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "id=" + id +
                ", deptName='" + deptName + '\'' +
                '}';
    }
}

创建EmployeeMapper、DeptMapper接口文件和xml映射文件

public interface EmployeeMapper {}
public interface DeptMapper {}

EmployeeMapper.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.xiaoqiu.dao.EmployeeMapper">

</mapper>

DeptMapper.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.xiaoqiu.dao.DeptMapper">
</mapper>

配置全局配置文件mybatis-config.xml

<?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>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.cj.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/test" />
				<property name="username" value="root" />
				<property name="password" value="123456" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="EmployeeMapper.xml" />
		<mapper resource="DeptMapper.xml" />
	</mappers>
</configuration>

测试类

public class Test {
    public static void main(String[] args) throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
			
			//需要修改操作的代码

            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }
    public static SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }
}

insert、update、delete元素

属性含义
id命名空间中的唯-标识符
parameterType将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为MyBatis可以通过TypeHandler推断出具体传入语句的参数类型,默认值为unset。
flushCache将其设置为true ,任何时候只要语句被调用都会导致本地缓存和二级缓存都会被清空,默认值: true (对应插入、更新和删除语句)。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为unset (依赖驱动)。
statementTypeSTATEMENT , PREPARED或CALLABLE的一个。 这会让MyBatis分别使用Statement , PreparedStatement或CallableStatement ,默认值: PREPARED。
useGeneratedKeys(仅对insert和update有用)这会令MyBatis使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(比如:像MySQL和SQL Server这样的关系数据库管理系统的自动递增字段) ,默认值: false
keyProperty(仅对insert和update有用)唯一标记一个属性, MyBatis会通过getGeneratedKeys的返回值或者通过insert语句的selectKey子元素设置它的键值,默认: unset。
keyColumn(仅对insert和update有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像PostgreSQL )是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
databaseld如果配置了databaseldProvider . MyBatis会加载所有的不带databaseld或匹配当前databaseld的语句;如果带或者不带的语句都有,则不带的会被忽略。

1、EmployeeMapper接口中定义insert、update、delete对应的方法

void addEmp(Employee employee);

void updateEmp(Employee employee);

void deleteEmpById(Integer id);

2、映射文件配置对应的sql映射

<insert id="addEmp" parameterType="com.xiaoqiu.bean.Employee">
    insert into tbl_employee(last_name, email, gender,d_id) values (#{lastname},#{email},#{gender},#{dept.id})
</insert>
<update id="updateEmp" parameterType="com.xiaoqiu.bean.Employee">
    update tbl_employee set last_name=#{lastname},email=#{email},gender=#{gender},d_id=#{dept.id} where id = #{id}
</update>
<delete id="deleteEmpById" parameterType="com.xiaoqiu.bean.Employee">
    delete from tbl_employee where id =  #{id}
</delete>

parameterType:参数类型,可以省略

3、测试

try {
    EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
    //增
    Employee employee = new Employee(null, "李四", "lisi@qq.com", "1",new Dept(1002,"生产部"));
    mapper.addEmp(employee);
    sqlSession.commit();
} catch (Exception e) {
    e.printStackTrace();
}finally {
    sqlSession.close();
}

结果:

DEBUG 10-15 16:27:32,328 ==>  Preparing: insert into tbl_employee(last_name, email, gender,d_id) values (?,?,?,?)   (BaseJdbcLogger.java:145) 
DEBUG 10-15 16:27:32,378 ==> Parameters: 李四(String), lisi@qq.com(String), 1(String), 1002(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 16:27:32,382 <==    Updates: 1  (BaseJdbcLogger.java:145) 

Process finished with exit code 0

在这里插入图片描述

try {
    EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

    //改
    Employee tom = new Employee(2, "tom", "tom002@qq.com", "1",new Dept(1002,null));
    mapper.updateEmp(tom);
    
    sqlSession.commit();
} catch (Exception e) {
    e.printStackTrace();
}finally {
    sqlSession.close();
}

结果:

DEBUG 10-15 16:40:03,706 ==>  Preparing: update tbl_employee set last_name=?,email=?,gender=?,d_id=? where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 16:40:03,761 ==> Parameters: tom(String), tom002@qq.com(String), 1(String), 1002(Integer), 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 16:40:03,765 <==    Updates: 1  (BaseJdbcLogger.java:145) 

Process finished with exit code 0

在这里插入图片描述

try {
	 EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

	 //删
	 mapper.deleteEmpById(9);

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

结果:

DEBUG 10-15 16:43:38,360 ==>  Preparing: delete from tbl_employee where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 16:43:38,424 ==> Parameters: 9(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 16:43:38,427 <==    Updates: 1  (BaseJdbcLogger.java:145) 

Process finished with exit code 0

在这里插入图片描述

主键生成方式

若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置useGeneratedKeys=”true”,然后再把keyProperty 设置到目标属性上。

不自动生成主键时运行结果:

DEBUG 10-15 17:57:44,062 ==>  Preparing: insert into tbl_employee(last_name, email, gender,d_id) values (?,?,?,?)   (BaseJdbcLogger.java:145) 
DEBUG 10-15 17:57:44,111 ==> Parameters: 李四(String), lisi@qq.com(String), 1(String), 1002(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 17:57:44,114 <==    Updates: 1  (BaseJdbcLogger.java:145) 
null

Process finished with exit code 0

添加自动生成主键

<insert id="addEmp" parameterType="com.xiaoqiu.bean.Employee" useGeneratedKeys="true" keyProperty="id" >
    insert into tbl_employee(last_name, email, gender,d_id) values (#{lastname},#{email},#{gender},#{dept.id})
</insert>

mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();
 useGeneratedKeys=“true”:使用自增主键获取主键值策略
 keyProperty:指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性

try {
   EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
   //增
   Employee employee = new Employee(null, "李四", "lisi@qq.com", "1",new Dept(1002,"生产部"));
   mapper.addEmp(employee);
   System.out.println(employee.getId());

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

结果:

DEBUG 10-15 17:58:44,062 ==>  Preparing: insert into tbl_employee(last_name, email, gender,d_id) values (?,?,?,?)   (BaseJdbcLogger.java:145) 
DEBUG 10-15 17:58:44,111 ==> Parameters: 李四(String), lisi@qq.com(String), 1(String), 1002(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 17:58:44,114 <==    Updates: 1  (BaseJdbcLogger.java:145) 
10

Process finished with exit code 0

而对于不支持自增型主键的数据库(例如Oracle),则可以使用 selectKey 子元素:
selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用。

<insert id="addEmpOracle" databaseId="oracle">
    <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
        <!-- 编写查询主键的sql语句 -->
        <!-- BEFORE-->
        select EMPLOYEES_SEQ.nextval from dual
        <!-- AFTER:
         select EMPLOYEES_SEQ.currval from dual -->
    </selectKey>

    <!-- 插入时的主键是从序列中拿到的 -->
    <!-- BEFORE:-->
    insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
    values(#{id},#{lastname},#{email})
    <!-- AFTER:
    insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
    values(employees_seq.nextval,#{lastName},#{email}) -->
</insert>

Oracle不支持自增;Oracle使用序列来模拟自增;每次插入的数据的主键是从序列中拿到的值
 keyProperty:查出的主键值封装给javaBean的哪个属性
 order=“BEFORE”:当前sql在插入sql之前运行
     AFTER:当前sql在插入sql之后运行
 resultType:查出的数据的返回值类型
BEFORE运行顺序:
  先运行selectKey查询id的sql;查出id值封装给javaBean的id属性
  在运行插入的sql;就可以取出id属性对应的值
AFTER运行顺序:
  先运行插入的sql(从序列中取出新值作为id)
  再运行selectKey查询id的sql

属性含义
keyPropertyselectKey语句结果应该被设置的目标属性。
keyColumn匹配属性的返回结果集中的列名称。
resultType返回结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。
order可以被设置为BEFORE或AFTER。如果设置为BEFORE ,那么它会首先选择主键,设置keyProperty然后执行插入语句。如果设置为AFTER ,那么先执行插入语句,然后是selectKey元素
statementType与前面相同, MyBatis支持STATEMENT , PREPARED和CALLABLE语句的映射类型,分别代表PreparedStatement和CallableStatement类型

参数处理(Parameters)

1、单个参数

可以接受基本类型,对象类型,集合类型的值。这种情况MyBatis可直接使用这个参数,不需要经过任何处理。

#{参数名/任意名}:取出参数值。

例:
EmployeeMapper接口中增加根据id查询employee的方法

Employee getEmpById(Integer id);
<select id="getEmpById" resultType="com.xiaoqiu.bean.Employee">
    select id, last_name lastName, email, gender,d_id from tbl_employee where id = #{id}
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	Employee employee = mapper.getEmpById(2);
	System.out.println(employee);

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

结果:

DEBUG 10-15 18:27:00,933 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 18:27:00,991 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 18:27:01,028 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=2, lastname='tom', email='tom002@qq.com', gender='1', dept=null}

Process finished with exit code 0
2、多个参数

示例:
EmployeeMapper接口中增加根据id和lastname查询employee的方法

Employee getEmpByIdAndLastname(Integer id,String lastname);

错误示例:

<select id="getEmpByIdAndLastname" resultType="com.xiaoqiu.bean.Employee">
    select id, last_name lastName, email, gender,d_id from tbl_employee where id = #{id} and last_name = #{lastname}
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	Employee lucy = mapper.getEmpByIdAndLastname(7, "lucy");
    System.out.println(lucy);

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

结果:

Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [0, 1, param1, param2]
Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [0, 1, param1, param2]

正确示例1:使用paramN

多个参数会被封装成 一个map,
 key:param1…paramN,或者参数的索引也可以
 value:传入的参数值
 #{}就是从map中获取指定的key的值;

<select id="getEmpByIdAndLastname" resultType="com.xiaoqiu.bean.Employee">
    select id, last_name lastName, email, gender,d_id from tbl_employee where id = #{param1} and last_name = #{param2}
</select>

结果:

DEBUG 10-15 18:47:20,705 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where id = ? and last_name = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 18:47:20,779 ==> Parameters: 7(Integer), lucy(String)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 18:47:20,823 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=7, lastname='lucy', email='lucy@qq.com', gender='0', dept=null}

Process finished with exit code 0
3、命名参数

当参数很多的时候,paramN也不太好区分,这时候可以选择命名参数。

【命名参数】:明确指定封装参数时map的key;@Param(“id”)
  多个参数会被封装成 一个map,
  key:使用@Param注解指定的值
  value:参数值
  #{指定的key}取出对应的参数值

EmployeeMapper接口中使用@param注解指定

Employee getEmpByIdAndLastname(@Param("id") Integer id, @Param("lastname") String lastname);

这时候映射文件中即可使用命名参数

<select id="getEmpByIdAndLastname" resultType="com.xiaoqiu.bean.Employee">
    select id, last_name lastName, email, gender,d_id from tbl_employee where id = #{id} and last_name = #{lastname}
</select>

结果:

DEBUG 10-15 18:55:32,991 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where id = ? and last_name = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 18:55:33,033 ==> Parameters: 7(Integer), lucy(String)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 18:55:33,063 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=7, lastname='lucy', email='lucy@qq.com', gender='0', dept=null}

Process finished with exit code 0
4、POJO实体对象参数

如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo。

#{pojo属性名}:取出传入的pojo的属性值

EmployeeMapper接口中增加getEmpByPojo方法

Employee getEmpByPojo(Employee employee);
<select id="getEmpByPojo" parameterType="com.xiaoqiu.bean.Employee" resultType="com.xiaoqiu.bean.Employee">
    select id, last_name lastName, email, gender,d_id from tbl_employee where id = #{id} and last_name = #{ lastname }
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	Employee employee = new Employee(1, "张三", null, null);
    System.out.println(mapper.getEmpByPojo(employee));

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

结果:

DEBUG 10-15 19:18:16,301 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where id = ? and last_name = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 19:18:16,418 ==> Parameters: 1(Integer), 张三(String)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 19:18:16,495 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=1, lastname='张三', email='zhangsan@qq.com', gender='1', dept=null}

Process finished with exit code 0
5、Map传参

如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map

#{map中的key}:取出map中对应的值

EmployeeMapper接口中增加getEmpByMap方法

Employee getEmpByMap(Map<String,Object> map);
<select id="getEmpByMap" resultType="com.xiaoqiu.bean.Employee">
    select id, last_name lastName, email, gender,d_id from tbl_employee where id = #{id} and last_name = #{ lastname }
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	Map<String,Object> map = new HashMap<>();
    map.put("id",1);
    map.put("lastname","张三");
    Employee empByMap = mapper.getEmpByMap(map);
    System.out.println(empByMap);

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

结果:

DEBUG 10-15 19:32:13,717 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where id = ? and last_name = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 19:32:13,766 ==> Parameters: 1(Integer), 张三(String)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 19:32:13,810 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=1, lastname='张三', email='zhangsan@qq.com', gender='1', dept=null}

Process finished with exit code 0
6、TO传参

如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象(即将需要传参的参数写一个对象,把这些参数封装成这个对象的属性,然后同pojo用法一致)

7、扩展
a、接口中一个加了@param,一个没加

Employee getEmp(@Param(“id”)Integer id,String lastName);
取值:id==>#{id或param1} lastName==>#{param2}

b、接口中有实体类,实体类加了@param

Employee getEmp(Integer id,@Param(“e”)Employee emp);
取值:id==>#{param1} lastName===>#{param2.lastName或者e.lastName}

c、参数中有list

特别注意:如果是Collection(List、Set)类型或者是数组, 也会特殊处理。也是把传入的list或者数组封装在map中。
key:Collection(collection),如果是List还可以使用这个key(list)、数组(array)

Employee getEmpById(List ids);
取值:取出第一个id的值: #{ ids[0]}或者#{list[0]}

总结:参数多时会封装map,为了不混乱,我们可以使用@Param来指定封装时使用的key;
#{key}就可以取出map中的值;

参数值的获取

#{}:可以获取map中的值或者pojo对象属性的值;获取参数的值,预编译到SQL中。安全。
${}:可以获取map中的值或者pojo对象属性的值;获取参数的值,拼接到SQL中。有SQL注入问题。
大多情况下,我们去参数的值都应该去使用#{};

原生jdbc不支持占位符的地方我们就可以使用${}进行取值, 比如分表、排序。。。;
例:按照年份分表拆分

select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} 

#{}:更丰富的用法:
 规定参数的一些规则:
  javaType、 jdbcType、 mode(存储过程)、 numericScale、
  resultMap、 typeHandler、 jdbcTypeName、 expression(未来准备支持的功能)

jdbcType通常需要在某种特定的条件下被设置:
实际上通常被设置的是:
 在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错);
 JdbcType OTHER:无效的类型;因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,oracle不能正确处理;

由于全局配置中:jdbcTypeForNull=OTHER;oracle不支持;两种办法
1、取值时指定,只影响当前的:#{email,jdbcType=OTHER};
2、修改全局配置。影响全局:<setting name=“jdbcTypeForNull” value=“NULL”/>

mode 属性允许指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像在获取输出参数时所期望的那样。

select元素

Select元素来定义查询操作。

常用的三个属性:
Id:唯一标识符。用来引用这条语句,需要和接口的方法名一致
parameterType:参数类型。可以不传,MyBatis会根据TypeHandler自动推断
resultType:返回值类型。 别名或者全类名,如果返回的是集合,定义集合中元素的类型。不能和resultMap同时使用

属性含义
parameterType将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的.因为MyBatis可以通过TypeHandler推断出具体传入语句的参数,默认值为unset.
resultType从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合那应该是集合可以包含的类型,而不能是集合本身该属性。和resultMap 不能同时使用。
resultMap外部resultMap的命名引用。和resultType属性不能同时使用。
flushCache将其设置为true ,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值: false
useCache将其设置为true ,将会导致本条语句的结果被二级缓存。默认值:对select元素为true
timeout这个设置是在抛出异常之前.驱动程序等待数据库返回请求结果的秒数。默认值为unset (依赖驱动)。
fetchSize影响驱动程序每次批量返回的结果行数。默认值为unset (依赖驱动)。
statementTypeSTATEMENT , PREPARED或CALLABLE的一个。 这会让MyBatis分别使用Statement , PreparedStatement或CallableStatement ,默认值: PREPARED。
resultSetTypeFORWARD_ ONLY . SCROLL _SENSITIVE或SCROLL _INSENSITIVE中的一个,默认值为unset (依赖驱动)
databaseld如果配置了databaseldProvider , MyBatis会加载所有的不带databaseld或匹配当前databaseld的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultOrdered这个设置仅针对嵌套结果select语句适用:如果为true ,就假设包含了嵌套结果集或是分组,这样当返回-个主结果行,就不会发生有对前面结果集引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值: false
resultSets这个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一 个名称,名称是逗号分隔的
1、查询返回List

EmployeeMapper接口中增加名字模糊查询employee的方法

List<Employee> getEmpByNameLike(String lastname);
<select id="getEmpByNameLike" resultType="com.xiaoqiu.bean.Employee">
    select id, last_name lastName, email, gender,d_id from tbl_employee where last_name like #{lastname}
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	mapper.getEmpByNameLike("%j%").forEach(System.out::println);
	
	sqlSession.commit();
} catch (Exception e) {
	e.printStackTrace();
}finally {
	sqlSession.close();
}

结果:

DEBUG 10-15 20:44:20,146 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where last_name like ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 20:44:20,276 ==> Parameters: %j%(String)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 20:44:20,360 <==      Total: 2  (BaseJdbcLogger.java:145) 
Employee{id=3, lastname='jerry', email='jerry@qq.com', gender='0', dept=null}
Employee{id=4, lastname='jeck', email='jeck@qq.com', gender='1', dept=null}

Process finished with exit code 0
2、查询一条记录返回Map

EmployeeMapper接口中增加方法

//返回一条记录map,key就是列名,value就是对应的值
Map<String,Object> getEmpByIdReturnMap(Integer id);
<select id="getEmpByIdReturnMap" resultType="map">
    select id, last_name lastName, email, gender,d_id from tbl_employee where id = #{id}
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	System.out.println(mapper.getEmpByIdReturnMap(5));

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

结果:

DEBUG 10-15 20:54:27,364 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 20:54:27,415 ==> Parameters: 5(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 20:54:27,451 <==      Total: 1  (BaseJdbcLogger.java:145) 
{lastName=tom, gender=1, d_id=1005, id=5, email=tom@qq.com}

Process finished with exit code 0
3、查询多条记录返回Map

EmployeeMapper接口中增加方法

//返回多条记录map,key就是主键,value就是对应javabean
@MapKey("id")//告诉MyBatis封装时使用id属性作为主键
Map<Integer,Employee> getEmpByNameReturnMap(String lastname);
<select id="getEmpByNameReturnMap" resultType="com.xiaoqiu.bean.Employee">
   select id, last_name lastName, email, gender,d_id from tbl_employee where last_name like #{lastname}
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	System.out.println(mapper.getEmpByNameReturnMap("%j%"));

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

结果:

DEBUG 10-15 21:02:55,600 ==>  Preparing: select id, last_name lastName, email, gender,d_id from tbl_employee where last_name like ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 21:02:55,649 ==> Parameters: %j%(String)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 21:02:55,688 <==      Total: 2  (BaseJdbcLogger.java:145) 
{3=Employee{id=3, lastname='jerry', email='jerry@qq.com', gender='0', dept=null}, 4=Employee{id=4, lastname='jeck', email='jeck@qq.com', gender='1', dept=null}}

Process finished with exit code 0
4、自动映射

当我们javabean与数据库字段名字不一致时,直接查询封装会报错。
解决方法:
1、查询语句中起别名
2、数据库命名与javabean命名符号驼峰命名规则,则开启mapUnderscoreToCamelCase=true。
3、自定义resultMap

全局setting设置autoMappingBehavior

  • autoMappingBehavior默认是PARTIAL,开启自动映射的功能。唯一的要求是列名和javaBean属性名一致
  • 如果autoMappingBehavior设置为null则会取消自动映射
  • 数据库字段命名规范,POJO属性符合驼峰命名法,如A_COLUMN----->aColumn,我们可以开启自动驼峰命名规则映射功能,mapUnderscoreToCamelCase=true。
5、自定义resultMap,实现高级结果集映射。
  • constructor:类在实例化时, 用来注入结果到构造方法中
     idArg:ID 参数; 标记结果作为 ID 可以帮助提高整体效能
     arg:注入到构造方法的一个普通结果
  • id:一个 ID 结果; 标记结果作为 ID 可以帮助提高整体效能
  • result:注入到字段或 JavaBean 属性的普通结果
  • association:一个复杂的类型关联;许多结果将包成这种类型,嵌入结果映射 – 结果映射自身的关联,或者参考一个
  • collection:复杂类型的集,嵌入结果映射 – 结果映射自身的集,或者参考一个
  • discriminator:使用结果值来决定使用哪个结果映射.
     case:基于某些值的结果映射,嵌入结果映射 – 这种情形结果也映射它本身,因此可以包含很多相同的元素,或者它可以参照一个外部的结果映射。
id & result

id 和 result 映射一个单独列的值到简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段。

属性含义
property映射到列结果的字段或属性。例如: “username” “address.street.number” 。
column数据表的列名。通常和resultSet.getString(columnName)的返回值一致。
javaType一个Java类的完全限定名,或-一个类型别名。如果映射到一个JavaBean, MyBatis通常可以断定类型
jdbcTypeJDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。
typeHandler类型处理器。使用这个属性,可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。

示例

<resultMap id="myEmp" type="com.xiaoqiu.bean.Employee">
    <id column="id" property="id"/>
    <result column="last_name" property="lastname"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
</resultMap>
<select id="getEmpById"  resultMap="myEmp">
    select * from tbl_employee where id = #{id}
</select>

映射规则:

  • resultMap自定义javabean封装规则:
      id : 唯一id方便引用
     type :自定义规则的Java类型
  • id指定主键列底层有优化:
     column :指定查询结果中哪一列
     property :指定对应的javaBean属性
  • result定义普通列封装规则:
     column : 指定查询结果中哪一列
      property: 指定对应的javaBean属性
  • 其他对应javabean的属性列的不指定会自动封装,但我们只要写resultMap就把全部的映射规则都写上。
  • resultMap:自定义结果集映射规则
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	System.out.println(mapper.getEmpById(2));
	sqlSession.commit();
} catch (Exception e) {
	e.printStackTrace();
}finally {
	sqlSession.close();
}

结果:

DEBUG 10-15 21:46:49,147 ==>  Preparing: select * from tbl_employee where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-15 21:46:49,198 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-15 21:46:49,253 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=2, lastname='tom', email='tom002@qq.com', gender='1', dept=null}

Process finished with exit code 0
association

当遇到复杂对象映射时,比如说POJO中的属性可能会是一个对象,我们可以使用联合查询,并以级联属性的方式封装对象。

案例:查询Employee的同时查询员工对应的部门

EmployeeMapper接口中增加方法

Employee getEmpAndDept(Integer id);
示例一:不使用association的级联属性封装结果集
<resultMap type="com.xiaoqiu.bean.Employee" id="MyDifEmp">
    <id column="id" property="id"/>
    <result column="last_name" property="lastname"/>
    <result column="gender" property="gender"/>
    <result column="email" property="email"/>
    <result column="did" property="dept.id"/>
    <result column="dept_name" property="dept.deptName"/>
</resultMap>
<select id="getEmpAndDept" resultMap="MyDifEmp">
    SELECT e.id id,e.last_name last_name,e.email email, e.gender gender,e.d_id d_id,
           d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
    WHERE e.d_id=d.id AND e.id=#{id}
</select>
try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	System.out.println(mapper.getEmpAndDept(2));

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

结果:

DEBUG 10-16 15:32:34,671 ==>  Preparing: SELECT e.id id,e.last_name last_name,e.email email, e.gender gender,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:32:34,718 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:32:34,765 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=2, lastname='tom', email='tom002@qq.com', gender='1', dept=Dept{id=1002, deptName='生产部'}}

Process finished with exit code 0
示例二:使用association定义关联的单个对象的封装规则即association嵌套结果集
<resultMap type="com.xiaoqiu.bean.Employee" id="MyDifEmp">
    <id column="id" property="id"/>
    <result column="last_name" property="lastname"/>
    <result column="gender" property="gender"/>
    <result column="email" property="email"/>
    <association property="dept" javaType="com.xiaoqiu.bean.Dept">
        <id column="did" property="id"></id>
        <result column="dept_name" property="deptName"></result>
    </association>
</resultMap>
<select id="getEmpAndDept" resultMap="MyDifEmp">
    SELECT e.id id,e.last_name last_name,e.email email, e.gender gender,e.d_id d_id,
           d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
    WHERE e.d_id=d.id AND e.id=#{id}
</select>

使用association定义关联的单个对象的封装规则:
  association可以指定联合的javaBean对象
 property=“dept”:指定哪个属性是联合的对象
 javaType:指定这个属性对象的类型[不能省略]

测试代码同上,结果:

DEBUG 10-16 15:39:02,921 ==>  Preparing: SELECT e.id id,e.last_name last_name,e.email email, e.gender gender,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:39:02,968 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:39:03,031 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=2, lastname='tom', email='tom002@qq.com', gender='1', dept=Dept{id=1002, deptName='生产部'}}

Process finished with exit code 0
示例三:使用association进行分步查询(分段查询)

1、先按照员工id查询员工信息
2、根据查询员工信息中的d_id值去部门表查出部门信息
3、部门设置到员工中;

DeptMapper接口中增加方法

Dept getDeptById(Integer id);

DeptMapper映射文件

<select id="getDeptById" resultType="com.xiaoqiu.bean.Dept">
    select id,dept_name deptName from tbl_dept where id = #{id}
</select>

EmployeeMapper接口中增加方法

Employee getEmpAndDeptStep(Integer id);

EmployeeMapper映射文件

<resultMap type="com.xiaoqiu.bean.Employee" id="MyEmpByStep">
    <id column="id" property="id"/>
    <result column="last_name" property="lastname"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
    <association column="d_id"
                 select="com.xiaoqiu.dao.DeptMapper.getDeptById"
                 property="dept">
    </association>
</resultMap>
<select id="getEmpAndDeptStep" resultMap="MyEmpByStep">
    select * from tbl_employee where id=#{id}
</select>

association定义关联对象的封装规则:
 select:表明当前属性是调用select指定的方法查出的结果
 column:指定将哪一列的值传给这个方法
 流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性

try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	System.out.println(mapper.getEmpAndDeptStep(2));
	
	sqlSession.commit();
} catch (Exception e) {
	e.printStackTrace();
}finally {
	sqlSession.close();
}

结果:

DEBUG 10-16 15:53:08,624 ==>  Preparing: select * from tbl_employee where id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:53:08,671 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:53:08,749 <==      Total: 1  (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:53:08,749 ==>  Preparing: select id,dept_name deptName from tbl_dept where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:53:08,749 ==> Parameters: 1002(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 15:53:08,749 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=2, lastname='tom', email='tom002@qq.com', gender='1', dept=Dept{id=1002, deptName='生产部'}}

Process finished with exit code 0
示例四:分段查询之延迟加载

在不开启延迟加载的情况下,每次我们采用分段查询,它都是将多条sql查询语句同时执行,如果开启延迟加载(懒加载、按需加载),当我们需要使用其他表的信息时,它才会再去加载查询其他表的信息。开启方法:分段查询的基础之上加上两个配置。

配置全局配置文件mybatis-config.xml

<settings>
	<!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
	<setting name="lazyLoadingEnabled" value="true"/>
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>

测试一:不使用部门信息

try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	Employee employee = mapper.getEmpAndDeptStep(2);
    System.out.println(employee.getLastname());

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

结果:只有一条查询语句

DEBUG 10-16 16:10:12,753 ==>  Preparing: select * from tbl_employee where id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:10:12,799 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:10:12,909 <==      Total: 1  (BaseJdbcLogger.java:145) 
tom

Process finished with exit code 0

测试二:使用部门信息

try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	Employee employee = mapper.getEmpAndDeptStep(2);
    System.out.println(employee.getDept());

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

结果:两条查询语句

DEBUG 10-16 16:11:32,939 ==>  Preparing: select * from tbl_employee where id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:11:32,985 ==> Parameters: 2(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:11:33,064 <==      Total: 1  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:11:33,064 ==>  Preparing: select id,dept_name deptName from tbl_dept where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:11:33,064 ==> Parameters: 1002(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:11:33,064 <==      Total: 1  (BaseJdbcLogger.java:145) 
Dept{id=1002, deptName='生产部'}

Process finished with exit code 0
Collection集合类型

案例:查询部门的时候将部门对应的所有员工信息也查询出来

示例一:Collection嵌套结果集

DeptMapper接口中增加方法

Dept getDeptByIdPlus(Integer id);

DeptMapper映射文件

<resultMap type="com.xiaoqiu.bean.Dept" id="MyDept">
   <id column="did" property="id"/>
   <result column="dept_name" property="deptName"/>
   <collection ofType="com.xiaoqiu.bean.Employee" property="emps">
       <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="getDeptByIdPlus" resultMap="MyDept">
   SELECT d.id did,d.dept_name dept_name,
          e.id eid,e.last_name last_name,e.email email,e.gender gender
   FROM tbl_dept d
       LEFT JOIN tbl_employee e
       ON d.id=e.d_id
   WHERE d.id=#{id}
</select>

使用collection标签定义关联的集合类型的属性封装规则:
 collection定义关联集合类型的属性的封装规则
 ofType:指定集合里面元素的类型

测试代码:

try {
	DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
    Dept dept = mapper.getDeptByIdPlus(1001);
    System.out.println(dept);
    dept.getEmps().forEach(System.out::println);
	sqlSession.commit();
} catch (Exception e) {
	e.printStackTrace();
}finally {
	sqlSession.close();
}

结果:

DEBUG 10-16 16:36:45,729 ==>  Preparing: SELECT d.id did,d.dept_name dept_name, e.id eid,e.last_name last_name,e.email email,e.gender gender FROM tbl_dept d LEFT JOIN tbl_employee e ON d.id=e.d_id WHERE d.id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:36:45,776 ==> Parameters: 1001(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:36:45,823 <==      Total: 2  (BaseJdbcLogger.java:145) 
Dept{id=1001, deptName='研发部'}
Employee{id=1, lastname='张三', email='zhangsan@qq.com', gender='1', dept=null}
Employee{id=7, lastname='lucy', email='lucy@qq.com', gender='0', dept=null}

Process finished with exit code 0
示例二:Collection分步查询

EmployeeMapper接口中增加方法

List<Employee> getEmpsByDeptId(Integer DeptId);

EmployeeMapper映射文件

<select id="getEmpsByDeptId" resultType="com.xiaoqiu.bean.Employee">
   select id, last_name lastName, email, gender  from tbl_employee where d_id=#{deptId}
</select>

DeptMapper接口中增加方法

Dept getDeptByIdStep(Integer id);

DeptMapper映射文件

<resultMap type="com.xiaoqiu.bean.Dept" id="MyDeptStep">
    <id column="id" property="id"/>
    <id column="dept_name" property="deptName"/>
    <collection column="id"
                select="com.xiaoqiu.dao.EmployeeMapper.getEmpsByDeptId"
                property="emps" >
    </collection>
</resultMap>
<select id="getDeptByIdStep" resultMap="MyDeptStep">
    select id,dept_name from tbl_dept where id=#{id}
</select>

测试代码

try {
	DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
    Dept dept = mapper.getDeptByIdStep(1001);
    System.out.println(dept);
    dept.getEmps().forEach(System.out::println);
} catch (Exception e) {
	e.printStackTrace();
}finally {
	sqlSession.close();
}

结果:

DEBUG 10-16 16:52:25,697 ==>  Preparing: select id,dept_name from tbl_dept where id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:52:25,744 ==> Parameters: 1001(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:52:25,822 <==      Total: 1  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:52:25,837 ==>  Preparing: select id, last_name lastName, email, gender from tbl_employee where d_id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:52:25,837 ==> Parameters: 1001(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 16:52:25,837 <==      Total: 2  (BaseJdbcLogger.java:145) 
Dept{id=1001, deptName='研发部'}
Employee{id=1, lastname='张三', email='zhangsan@qq.com', gender='1', dept=null}
Employee{id=7, lastname='lucy', email='lucy@qq.com', gender='0', dept=null}

Process finished with exit code 0
示例三:Collection延迟加载

在不开启延迟加载的情况下,每次我们采用分段查询,它都是将多条sql查询语句同时执行,如果开启延迟加载(懒加载、按需加载),当我们需要使用其他表的信息时,它才会再去加载查询其他表的信息。开启方法:分步查询的基础之上加上两个配置。

配置全局配置文件mybatis-config.xml

<settings>
	<!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
	<setting name="lazyLoadingEnabled" value="true"/>
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>
扩展-多列值封装map传递
  • 分步查询的时候通过column指定,将对应的列的数据传递过去,我们有时需要传递多列数据,这时候可以使用{key1=column1,key2=column2…}的形式传递。
<collection column="{deptId=id}"
            select="com.xiaoqiu.dao.EmployeeMapper.getEmpsByDeptId"
            property="emps" >
</collection>
  • association或者collection标签的fetchType=eager/lazy可以覆盖全局的延迟加载策略,指定立即加载(eager)或者延迟加载(lazy)。
<collection column="id"
            select="com.xiaoqiu.dao.EmployeeMapper.getEmpsByDeptId"
            property="emps"
            fetchType="lazy">
</collection>
  • discriminator鉴别器
    mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为,即根据结果值来决定使用哪个结果映射。

案例:(只是为了演示)
封装Employee:
如果查出的是女生:就把部门信息查询出来,否则不查询;
如果是男生,把last_name这一列的值赋值给email;

<resultMap type="com.xiaoqiu.bean.Employee" id="MyEmpDis">
    <id column="id" property="id"/>
    <result column="last_name" property="lastname"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
    <discriminator  column="gender" javaType="string">
        <case value="0" resultType="com.xiaoqiu.bean.Employee">
            <association property="dept"
                         select="com.xiaoqiu.dao.DeptMapper.getDeptById"
                         column="d_id">
            </association>
        </case>
        <case value="1" resultType="com.xiaoqiu.bean.Employee">
            <id column="id" property="id"/>
            <result column="last_name" property="lastname"/>
            <result column="last_name" property="email"/>
            <result column="gender" property="gender"/>
        </case>
    </discriminator>
</resultMap>
<select id="getEmpAndDeptStep" resultMap="MyEmpDis">
    select * from tbl_employee where id=#{id}
</select>
  • discriminator:
     column:指定判定的列名
      javaType:列值对应的java类型
  • case : 基于某些值的结果映射
    嵌入结果映射 这种情形结果也映射它本身,因此可以包含很多相同的元素,或者它可以参照一个外部的结果映射。
      value:case匹配value值选择结果映射
      resultType:指定封装的结果类型,不能缺少

测试1:男生

try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	System.out.println(mapper.getEmpAndDeptStep(1));
	
	sqlSession.commit();
} catch (Exception e) {
	e.printStackTrace();
}finally {
	sqlSession.close();
}

结果:

DEBUG 10-16 17:31:42,589 ==>  Preparing: select * from tbl_employee where id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 17:31:42,667 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 17:31:42,698 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=1, lastname='张三', email='张三', gender='1', dept=null}

Process finished with exit code 0

测试2:女生

try {
	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
	
	System.out.println(mapper.getEmpAndDeptStep(3));
	
	sqlSession.commit();
} catch (Exception e) {
	e.printStackTrace();
}finally {
	sqlSession.close();
}

结果:

DEBUG 10-16 17:32:27,611 ==>  Preparing: select * from tbl_employee where id=?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 17:32:27,674 ==> Parameters: 3(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 17:32:27,752 <==      Total: 1  (BaseJdbcLogger.java:145) 
DEBUG 10-16 17:32:27,752 ==>  Preparing: select id,dept_name deptName from tbl_dept where id = ?   (BaseJdbcLogger.java:145) 
DEBUG 10-16 17:32:27,752 ==> Parameters: 1003(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 10-16 17:32:27,752 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=3, lastname='jerry', email='jerry@qq.com', gender='0', dept=Dept{id=1003, deptName='销售部'}}

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值