MyBatis(4)——Mapper映射文件_SELECT

查询语句是 MyBatis 中最常用的元素之一,光能把数据存到数据库中价值并不大,如果还能重新取出来才有用,多数应用也都是查询比修改要频繁。

<select > </select>标签属性参考表:

Select Attributes
属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。
parameterMap这是引用外部 parameterMap 的已经被废弃的方法。使用内联参数映射和 parameterType 属性。
resultType从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。
resultMap外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 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 (依赖驱动)。
databaseId如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultOrdered这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组了,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。
resultSets这个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。

一、select返回值

1、返回list

mapper接口:

public abstract List<Employee> getEmpsByLastNameLike(String lastName);

mapper文件:

<!-- public List<Employee> getEmpsByLastNameLike(String lastName); -->
<!--resultType:如果返回的是一个集合,要写集合中元素的类型  -->
<select id="getEmpsByLastNameLike" resultType="com.atguigu.mybatis.bean.Employee">
	select * from tbl_employee where last_name like #{lastName}
</select>

2、返回map

(1)返回单条记录的map: Map<String, Object>:key为列名称,value为对应的值

mapper接口:

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

mapper文件:resultType="map",resultType不再指定为元素类型,而是hashmap类型。

<!--public Map<String, Object> getEmpByIdReturnMap(Integer id);  -->
<select id="getEmpByIdReturnMap" resultType="map">
	select * from tbl_employee where id=#{id}
</select>

查询结果:

{manager_id=100, department_id=50, job_id=ST_MAN, employee_id=120, last_name=Weiss, phone_number=650.123.1234, hire_date=2004-07-18, salary=8000.00, first_name=Matthew, email=MWEISS}

(2)多条记录封装一个map:Map<Integer,Employee>:key为其中单条记录的主键,value是记录封装后的javaBean

mapper接口:@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key

@MapKey("lastName")
public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);

mapper文件:

<!-- public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName); -->
<select id="getEmpByLastNameLikeReturnMap" resultType="com.starfall.mybaits.entity.Employee">
	SELECT
		employee_id AS employeeId,
		first_name AS firstName,
		last_name AS lastName,
		email AS email,
		phone_number AS phoneNumber,
		hire_date AS hireDate,
		job_id AS jobId,
		salary AS salary,
		manager_id AS managerId,
		department_id AS departmentId
	FROM
		employee
	WHERE
		last_name like #{lastName}
</select>

查询结果:

{Ernst=Employee [employeeId=104, firstName=Bruce, lastName=Ernst, email=BERNST, phoneNumber=590.423.4568, hireDate=Mon May 21 00:00:00 CST 2007, jobId=IT_PROG, salary=6000.00, managerId=103, departmentId=60], Everett=Employee [employeeId=193, firstName=Britney, lastName=Everett, email=BEVERETT, phoneNumber=650.501.2876, hireDate=Thu Mar 03 00:00:00 CST 2005, jobId=SH_CLERK, salary=3900.00, managerId=123, departmentId=50], Errazuriz=Employee [employeeId=147, firstName=Alberto, lastName=Errazuriz, email=AERRAZUR, phoneNumber=011.44.1344.429278, hireDate=Thu Mar 10 00:00:00 CST 2005, jobId=SA_MAN, salary=12000.00, managerId=100, departmentId=80]}

二、resultMap

1、高级结果映射

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来, 并在一些情形下允许你做一些 JDBC 不支持的事情。 实际上,在对复杂语句进行联合映射的时候,它很可能可以代替数千行的同等功能的代码。 ResultMap 的设计思想是,简单的语句不需要明确的结果映射,而复杂一点的语句只需要描述它们的关系就行了。

<!-- 超复杂的 Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>
  </constructor>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
    <result property="favouriteSection" column="author_favourite_section"/>
  </association>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <collection property="tags" ofType="Tag" >
      <id property="id" column="tag_id"/>
    </collection>
    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>

(1)ResultMap标签

ResultMap标签的属性
属性描述
id当前命名空间中的一个唯一标识,用于标识一个result map.
type类的完全限定名, 或者一个类型别名 (内置的别名可以参考上面的表格).
autoMapping如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属性会覆盖全局的属性 autoMappingBehavior。默认值为:unset。

(2)id 标签:<id property="id" column="post_id"/>

id 表示的结果将是对象的标识属性,这会在比较对象实例时用到。 这样可以提高整体的性能,尤其是缓存和嵌套结果映射(也就是联合映射)的时候。

result标签:<result property="subject" column="post_subject"/>

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

Id和Result标签的属性
属性描述
property映射到列结果的字段或属性。如果用来匹配的 JavaBeans 存在给定名字的属性,那么它将会被使用。否则 MyBatis 将会寻找给定名称 property 的字段。 无论是哪一种情形,你都可以使用通常的点式分隔形式进行复杂属性导航。比如,你可以这样映射一些简单的东西: “username” ,或者映射到一些复杂的东西: “address.street.number” 。
column数据库中的列名,或者是列的别名。一般情况下,这和 传递给 resultSet.getString(columnName) 方法的参数一样。
javaType一个 Java 类的完全限定名,或一个类型别名(参考上面内建类型别名 的列表) 。如果你映射到一个 JavaBean,MyBatis 通常可以断定类型。 然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证期望的行为。
jdbcTypeJDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可能为 null 的值指定这个类型。
typeHandler我们在前面讨论过的默认类型处理器。使用这个属性,你可以覆盖默 认的类型处理器。这个属性值是一个类型处理 器实现类的完全限定名,或者是类型别名。

2、association

(1)一对一关联查询

查询Employee的同时查询员工对应的部门:Employee===Department

对应的javaBean

public class Employee {
	
	private Integer id;
	private String lastName;
	private String email;
	private String gender;
	private Department dept;
    
    //省略getter和setter方法。。。。
}

SQL:public Employee getEmpAndDept(Integer id);

<!-- 
	使用association定义关联的单个对象的封装规则;
 -->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2">
	<id column="id" property="id"/>
	<result column="last_name" property="lastName"/>
	<result column="gender" property="gender"/>

	<!--  association可以指定联合的javaBean对象
	property="dept":指定哪个属性是联合的对象
	javaType:指定这个属性对象的类型[不能省略]
	-->
	<association property="dept" javaType="com.atguigu.mybatis.bean.Department">
		<id column="did" property="id"/>
		<result column="dept_name" property="departmentName"/>
	</association>
</resultMap>
<!--  public Employee getEmpAndDept(Integer id);-->
<select id="getEmpAndDept" resultMap="MyDifEmp">
	SELECT
		e.id id,
		e.last_name last_name,
		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标签的属性说明:

属性描述
column来自数据库的列名,或重命名的列标签。这和通常传递给 resultSet.getString(columnName)方法的字符串是相同的。 column 注 意 : 要 处 理 复 合 主 键 , 你 可 以 指 定 多 个 列 名 通 过 column= ” {prop1=col1,prop2=col2} ” 这种语法来传递给嵌套查询语 句。这会引起 prop1 和 prop2 以参数对象形式来设置给目标嵌套查询语句。
select另外一个映射语句的 ID,可以加载这个属性映射需要的复杂类型。获取的 在列属性中指定的列的值将被传递给目标 select 语句作为参数。表格后面 有一个详细的示例。 select 注 意 : 要 处 理 复 合 主 键 , 你 可 以 指 定 多 个 列 名 通 过 column= ” {prop1=col1,prop2=col2} ” 这种语法来传递给嵌套查询语 句。这会引起 prop1 和 prop2 以参数对象形式来设置给目标嵌套查询语句。
fetchType可选的。有效值为 lazy和eager。 如果使用了,它将取代全局配置参数lazyLoadingEnabled。

(2)association分步查询

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

需要额外的一条SQL:根据部门id查部门表的信息

<!--public Department getDeptById(Integer id);  -->
<select id="getDeptById" resultType="com.atguigu.mybatis.bean.Department">
	select id,dept_name departmentName from tbl_dept where id=#{id}
</select>

SQL:改写sql映射的resultMap:public Employee getEmpAndDept(Integer id);

 <resultMap type="com.atguigu.mybatis.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定义关联对象的封装规则
		select:表明当前属性是调用select指定的方法查出的结果
		column:指定将哪一列的值传给这个方法
		
		流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
	 -->
	<association property="dept" 
		select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
		column="d_id">
	</association>
 </resultMap>
 <!--  public Employee getEmpByIdStep(Integer id);-->
 <select id="getEmpByIdStep" resultMap="MyEmpByStep">
	select * from tbl_employee where id=#{id}
 </select>

说明:column的值为resultMap中的一个result的column,而不是select对应方法的参数名称。建议column和select方法参数同名。

测试:

注意:在执行一种方法时候,例如:public List<Employee> getEmpAndDepByLastName(String lastName);

此时,会查处多条员工和部门的集合信息,有两个查询,一个查询员工,一个查询部门信息,则会出现“N+1 查询问题”。

N+1 查询问题可以是这样引起的:查询了一次员工列表,遍历N个员工的时候,进行N此查询部门的信息。

例如以下示例:

解决办法:对于这种情况,不建议使用延迟加载查询,应该使用join语句一次性的查询员工和部门的信息:

SELECT
	emp.*, dep.department_name
FROM
	employee emp
LEFT JOIN department dep 
ON emp.department_id = dep.department_id
WHERE
	emp.employee_id = 102

3、collection

(1)一对多关联查询

查询Department的同时查询该部门对应的员工:Department ==List<Employee>

对应javaBean

public class Department {
	
	private Integer id;
	private String departmentName;
	private List<Employee> emps;
    
    //省略getter和setter方法
}

SQL:public Department getDeptByIdPlus(Integer id);

<!--嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则  -->
<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDept">
	<id column="did" property="id"/>
	<result column="dept_name" property="departmentName"/>
	<!-- 
		collection定义关联集合类型的属性的封装规则 
		ofType:指定集合里面元素的类型
	-->
	<collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
		<!-- 定义这个集合中元素的封装规则 -->
		<id column="eid" property="id"/>
		<result column="last_name" property="lastName"/>
		<result column="email" property="email"/>
		<result column="gender" property="gender"/>
	</collection>
</resultMap>
<!-- public Department getDeptByIdPlus(Integer id); -->
<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标签属性说明:

     ofType:集合里面元素的类型

     javaType:集合的类型

(2)collection分步查询 

需要额外的一条SQL:根据部门id查询员工的信息

<select id="getEmpByDepId" resultType="com.starfall.mybaits.entity.Employee">
	select * from employee where department_id=#{departmentId}
</select>

SQL:改写sql映射的resultMap:public Department getDepAndEmpById(Integer departmentId);

<resultMap type="com.starfall.mybaits.entity.Department" id="depAndEmp">
 <id column="department_id" jdbcType="INTEGER" property="departmentId" />
 <result column="department_name" jdbcType="VARCHAR" property="departmentName" />
 <result column="manager_id" jdbcType="INTEGER" property="managerId" />
 <result column="location_id" jdbcType="INTEGER" property="locationId" />
 <collection 
 	property="emps" 
 	ofType="com.starfall.mybaits.entity.Employee"
 	select="com.starfall.mybaits.dao.EmployeeMapper.getEmpByDepId"
 	column="department_id"></collection>
</resultMap>
<!-- public Department getDepAndEmpById(Integer departmentId); -->
<select id="getDepAndEmpById" resultMap="depAndEmp">
	select * from department where department_id = #{departmentId,jdbcType=INTEGER}
</select>

测试:

4、延迟加载

延迟加载前提:需要使用association和collection的分步查询。

(1)全局配置:

lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认为false.

aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。

<settings>
	<setting name="lazyLoadingEnabled" value="true"/>
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>

(2)局部配置:

association和collection的局部配置在association和collection的标签配置属性:fetchType,有效值为 lazy和eager。 如果使用了,它将取代全局配置参数lazyLoadingEnabled。

5、扩展:多列的值传递过去

分步查询中,association和collection标签中的column:指定将哪一列的值传给select方法

多列的值:将多列的值封装map传递,示例:column="{key1=column1,key2=column2}"

6、鉴别器discriminator

mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为

示例:如果查出的是女生:就把部门信息查询出来,否则不查询;如果是男生,把last_name这一列的值赋值给email;

 <resultMap type="com.atguigu.mybatis.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"/>
	<!--
		column:指定判定的列名
		javaType:列值对应的java类型  -->
	<discriminator javaType="string" column="gender">
		<!--女生  resultType:指定封装的结果类型;不能缺少。/resultMap-->
		<case value="0" resultType="com.atguigu.mybatis.bean.Employee">
			<association property="dept" 
				select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
				column="d_id">
			</association>
		</case>
		<!--男生 ;如果是男生,把last_name这一列的值赋值给email; -->
		<case value="1" resultType="com.atguigu.mybatis.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>

上一章:MyBatis(3)——Mapper映射文件_参数处理

下一章:MyBatis(5)——Mapper映射文件_动态SQL

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值