映射文件
映射文件指导着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 (依赖驱动)。 | statementType | STATEMENT , 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">
select EMPLOYEES_SEQ.nextval from dual
</selectKey>
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(#{id},#{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
属性 | 含义 |
---|
keyProperty | selectKey语句结果应该被设置的目标属性。 | 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 (依赖驱动)。 | statementType | STATEMENT , PREPARED或CALLABLE的一个。 这会让MyBatis分别使用Statement , PreparedStatement或CallableStatement ,默认值: PREPARED。 | resultSetType | FORWARD_ 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<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接口中增加方法
@MapKey("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通常可以断定类型 | jdbcType | JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。 | 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
|