商务网站策划书,长春做网站新格公司,qq推广加好友,终身免费vps第三章 MyBatis
三、MyBatis 多表映射
2. 对一映射
2.1 需求说明
根据 ID 查询订单#xff0c;以及订单关联的用户的信息#xff01;
2.2 OrderMapper 接口
public interface OrderMapper {Order selectOrderWithCustomer(Integer orderId);
}2.3 OrderMapper.xml 配置…第三章 MyBatis
三、MyBatis 多表映射
2. 对一映射
2.1 需求说明
根据 ID 查询订单以及订单关联的用户的信息
2.2 OrderMapper 接口
public interface OrderMapper {Order selectOrderWithCustomer(Integer orderId);
}2.3 OrderMapper.xml 配置文件
!-- 创建resultMap实现“对一”关联关系映射 --
!-- id属性通常设置为这个resultMap所服务的那条SQL语句的id加上“ResultMap” --
!-- type属性要设置为这个resultMap所服务的那条SQL语句最终要返回的类型 --
resultMap idselectOrderWithCustomerResultMap typeorder!-- 先设置Order自身属性和字段的对应关系 --id columnorder_id propertyorderId/result columnorder_name propertyorderName/!-- 使用association标签配置“对一”关联关系 --!-- property属性在Order类中对一的一端进行引用时使用的属性名 --!-- javaType属性一的一端类的全类名 --association propertycustomer javaTypecustomer!-- 配置Customer类的属性和字段名之间的对应关系 --id columncustomer_id propertycustomerId/result columncustomer_name propertycustomerName//association/resultMap!-- Order selectOrderWithCustomer(Integer orderId); --
select idselectOrderWithCustomer resultMapselectOrderWithCustomerResultMapSELECT order_id,order_name,c.customer_id,customer_nameFROM t_order oLEFT JOIN t_customer cON o.customer_idc.customer_idWHERE o.order_id#{orderId}/select对应关系可以参考下图 2.4 Mybatis 全局注册 Mapper 文件
!-- 注册Mapper配置文件告诉Mybatis我们的Mapper配置文件的位置 --
mappers!-- 在mapper标签的resource属性中指定Mapper配置文件以“类路径根目录”为基准的相对路径 --mapper resourcemappers/OrderMapper.xml//mappers2.5 junit 测试程序
Slf4j
public class MyBatisTest {private SqlSession session;// junit会在每一个Test方法前执行BeforeEach方法BeforeEachpublic void init() throws IOException {session new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(mybatis-config.xml)).openSession();}Testpublic void testRelationshipToOne() {OrderMapper orderMapper session.getMapper(OrderMapper.class);// 查询Order对象检查是否同时查询了关联的Customer对象Order order orderMapper.selectOrderWithCustomer(2);log.info(order order);}// junit会在每一个Test方法后执行AfterEach方法AfterEachpublic void clear() {session.commit();session.close();}
}2.6 关键词
在“对一”关联关系中我们的配置比较多但是关键词就只有association 和 javaType
3. 对多映射
3.1 需求说明
查询客户和客户关联的订单信息
3.2 CustomerMapper 接口
public interface CustomerMapper {Customer selectCustomerWithOrderList(Integer customerId);}3.3 CustomerMapper.xml 文件
!-- 配置resultMap实现从Customer到OrderList的“对多”关联关系 --
resultMap idselectCustomerWithOrderListResultMaptypecustomer!-- 映射Customer本身的属性 --id columncustomer_id propertycustomerId/result columncustomer_name propertycustomerName/!-- collection标签映射“对多”的关联关系 --!-- property属性在Customer类中关联“多”的一端的属性名 --!-- ofType属性集合属性中元素的类型 --collection propertyorderList ofTypeorder!-- 映射Order的属性 --id columnorder_id propertyorderId/result columnorder_name propertyorderName//collection/resultMap!-- Customer selectCustomerWithOrderList(Integer customerId); --
select idselectCustomerWithOrderList resultMapselectCustomerWithOrderListResultMapSELECT c.customer_id,c.customer_name,o.order_id,o.order_nameFROM t_customer cLEFT JOIN t_order oON c.customer_ido.customer_idWHERE c.customer_id#{customerId}
/select对应关系可以参考下图 3.4 Mybatis 全局注册 Mapper 文件
!-- 注册Mapper配置文件告诉Mybatis我们的Mapper配置文件的位置 --
mappers!-- 在mapper标签的resource属性中指定Mapper配置文件以“类路径根目录”为基准的相对路径 --mapper resourcemappers/OrderMapper.xml/mapper resourcemappers/CustomerMapper.xml/
/mappers3.5 junit 测试程序
Test
public void testRelationshipToMulti() {CustomerMapper customerMapper session.getMapper(CustomerMapper.class);// 查询Customer对象同时将关联的Order集合查询出来Customer customer customerMapper.selectCustomerWithOrderList(1);log.info(customer.getCustomerId() customer.getCustomerId());log.info(customer.getCustomerName() customer.getCustomerName());ListOrder orderList customer.getOrderList();for (Order order : orderList) {log.info(order order);}
}3.6 关键词
在“对多”关联关系中同样有很多配置但是提炼出来最关键的就是“collection”和“ofType”
4. 多表映射总结
4.1 多表映射优化
setting 属性属性含义可选值默认值autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集无论是否嵌套。NONE, PARTIAL, FULLPARTIAL 我们可以将 autoMappingBehavior 设置为 full,进行多表 resultMap 映射的时候可以省略符合列和属性命名映射规则列名属性名或者开启驼峰映射也可以自定映射的 result 标签 修改 mybatis-sconfig.xml:
!--开启resultMap自动映射 --
setting nameautoMappingBehavior valueFULL/修改 teacherMapper.xml
resultMap idteacherMap typeteacherid propertytId columnt_id /!-- 开启自动映射,并且开启驼峰式支持!可以省略 result!--
!-- result propertytName columnt_name /--collection propertystudents ofTypestudent id propertysId columns_id /
!-- result propertysName columns_name /--/collection
/resultMap4.2 多表映射总结
关联关系配置项关键词所在配置文件和具体位置对一association 标签/javaType 属性/property 属性Mapper 配置文件中的 resultMap 标签内对多collection 标签/ofType 属性/property 属性Mapper 配置文件中的 resultMap 标签内
四、MyBatis 动态语句
1. 动态语句需求和简介
经常遇到很多按照很多查询条件进行查询的情况比如智联招聘的职位搜索等。其中经常出现很多条件不取值的情况在后台应该如何完成最终的 SQL 语句呢 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架你应该能理解根据不同条件拼接 SQL 语句有多痛苦例如拼接时要确保不能忘记添加必要的空格还要注意去掉列表最后一个列名的逗号。利用动态 SQL可以彻底摆脱这种痛苦。使用动态 SQL 并非一件易事但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言MyBatis 显著地提升了这一特性的易用性。如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式MyBatis 3 替换了之前的大部分元素大大精简了元素种类现在要学习的元素种类比原来的一半还要少。
2. if 和 where 标签
使用动态 SQL 最常见情景是根据条件包含 where / if 子句的一部分。比如
!-- ListEmployee selectEmployeeByCondition(Employee employee); --
select idselectEmployeeByCondition resultTypeemployeeselect emp_id,emp_name,emp_salary from t_emp!-- where标签会自动去掉“标签体内前面多余的and/or” --where!-- 使用if标签让我们可以有选择的加入SQL语句的片段。这个SQL语句片段是否要加入整个SQL语句就看if标签判断的结果是否为true --!-- 在if标签的test属性中可以访问实体类的属性不可以访问数据库表的字段 --if testempName ! null!-- 在if标签内部需要访问接口的参数时还是正常写#{} --or emp_name#{empName}/ifif testempSalary gt; 2000or emp_salary#{empSalary}/if!--第一种情况所有条件都满足 WHERE emp_name? or emp_salary?第二种情况部分条件满足 WHERE emp_salary?第三种情况所有条件都不满足 没有where子句--/where
/select3. set 标签
!-- void updateEmployeeDynamic(Employee employee) --
update idupdateEmployeeDynamicupdate t_emp!-- set emp_name#{empName},emp_salary#{empSalary} --!-- 使用set标签动态管理set子句并且动态去掉两端多余的逗号 --setif testempName ! nullemp_name#{empName},/ifif testempSalary lt; 3000emp_salary#{empSalary},/if/setwhere emp_id#{empId}!--第一种情况所有条件都满足 SET emp_name?, emp_salary?第二种情况部分条件满足 SET emp_salary?第三种情况所有条件都不满足 update t_emp where emp_id?没有set子句的update语句会导致SQL语法错误--
/update4. trim 标签了解 使用 trim 标签控制条件部分两端是否包含某些字符 prefix 属性指定要动态添加的前缀suffix 属性指定要动态添加的后缀prefixOverrides 属性指定要动态去掉的前缀使用“|”分隔有可能的多个值suffixOverrides 属性指定要动态去掉的后缀使用“|”分隔有可能的多个值
!-- ListEmployee selectEmployeeByConditionByTrim(Employee employee) --
select idselectEmployeeByConditionByTrim resultTypecom.atguigu.mybatis.entity.Employeeselect emp_id,emp_name,emp_age,emp_salary,emp_genderfrom t_emp!-- prefix属性指定要动态添加的前缀 --!-- suffix属性指定要动态添加的后缀 --!-- prefixOverrides属性指定要动态去掉的前缀使用“|”分隔有可能的多个值 --!-- suffixOverrides属性指定要动态去掉的后缀使用“|”分隔有可能的多个值 --!-- 当前例子用where标签实现更简洁但是trim标签更灵活可以用在任何有需要的地方 --trim prefixwhere suffixOverridesand|orif testempName ! nullemp_name#{empName} and/ifif testempSalary gt; 3000emp_salary#{empSalary} and/ifif testempAge lt; 20emp_age#{empAge} or/ifif testempGendermaleemp_gender#{empGender}/if/trim
/select5. choose / when / otherwise 标签 在多个分支条件中仅执行一个。 从上到下依次执行条件判断遇到的第一个满足条件的分支会被采纳被采纳分支后面的分支都将不被考虑如果所有的 when 分支都不满足那么就执行 otherwise 分支
!-- ListEmployee selectEmployeeByConditionByChoose(Employee employee) --
select idselectEmployeeByConditionByChoose resultTypecom.atguigu.mybatis.entity.Employeeselect emp_id,emp_name,emp_salary from t_empwherechoosewhen testempName ! nullemp_name#{empName}/whenwhen testempSalary lt; 3000emp_salary lt; 3000/whenotherwise11/otherwise/choose!--第一种情况第一个when满足条件 where emp_name?第二种情况第二个when满足条件 where emp_salary 3000第三种情况两个when都不满足 where 11 执行了otherwise--
/select6. foreach 标签
6.1 基本用法
用批量插入举例
!--collection属性要遍历的集合item属性遍历集合的过程中能得到每一个具体对象在item属性中设置一个名字将来通过这个名字引用遍历出来的对象separator属性指定当foreach标签的标签体重复拼接字符串时各个标签体字符串之间的分隔符open属性指定整个循环把字符串拼好后字符串整体的前面要添加的字符串close属性指定整个循环把字符串拼好后字符串整体的后面要添加的字符串index属性这里起一个名字便于后面引用遍历List集合这里能够得到List集合的索引值遍历Map集合这里能够得到Map集合的key--
foreach collectionempList itememp separator, openvalues indexmyIndex!-- 在foreach标签内部如果需要引用遍历得到的具体的一个对象需要使用item属性声明的名称 --(#{emp.empName},#{myIndex},#{emp.empSalary},#{emp.empGender})
/foreach6.2 批量更新时需要注意
上面批量插入的例子本质上是一条 SQL 语句而实现批量更新则需要多条 SQL 语句拼起来用分号分开。也就是一次性发送多条 SQL 语句让数据库执行。此时需要在数据库连接信息的 URL 地址中设置
alex.dev.urljdbc:mysql:///mybatis-example?allowMultiQueriestrue对应的 foreach 标签如下
!-- int updateEmployeeBatch(Param(empList) ListEmployee empList) --
update idupdateEmployeeBatchforeach collectionempList itememp separator;update t_emp set emp_name#{emp.empName} where emp_id#{emp.empId}/foreach
/update6.3 关于 foreach 标签的 collection 属性
如果没有给接口中 List 类型的参数使用Param 注解指定一个具体的名字那么在 collection 属性中默认可以使用 collection 或 list 来引用这个 list 集合。这一点可以通过异常信息看出来
Parameter empList not found. Available parameters are [arg0, collection, list]在实际开发中为了避免隐晦的表达造成一定的误会建议使用Param 注解明确声明变量的名称然后在 foreach 标签的 collection 属性中按照Param 注解指定的名称来引用传入的参数。
7. sql 片段
7.1 抽取重复的 SQL 片段
!-- 使用sql标签抽取重复出现的SQL片段 --
sql idmySelectSqlselect emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
/sql7.2 引用已抽取的 SQL 片段
!-- 使用include标签引用声明的SQL片段 --
include refidmySelectSql/