Mybatis 多表映射基于XML总结(一对一,一对多,多对多)
一、数据表
数据包括订单,产品,游客,会员。
1.1数据说明和数据关系:
产品表说明:
订单表说明:
会员表说明
旅客表说明
数据表的ER图
表与表之间的业务关系
旅客表(traverller)、订单表(orders)、会员表(member)、产品表(product)的id都是uuid()下随机生成的
- 订单表(orders)->产品表(product)一对一的关系
- 订单表(orders)->会员表(member) 一对一的关系
- 订单表(orders)->旅客表(traverller)多对多的关系(在Mybatis时中和一对多的处理很像,只不过多对多需要一张中间表)
二、实体类建立
Product实体类:
package domain;
import org.springframework.format.annotation.DateTimeFormat;
import util.DateUtils;
import java.io.Serializable;
import java.util.Date;
public class Product implements Serializable {
private String id; // 主键
private String productNum; // 编号 唯一
private String productName; // 名称
private String cityName; // 出发城市
//这个注解的目的是用spring来帮助处理这个属性从表单提交时的数据转换
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm")
private Date departureTime; // 出发时间
private String departureTimeStr;//出发时间格式化数据
private double productPrice; // 产品价格
private String productDesc; // 产品描述
private Integer productStatus; // 状态 0 关闭 1 开启
private String productStatusStr;//状态格式化
//省略getter 和 setter
}
Member实体类:
package domain;
import java.io.Serializable;
public class Member implements Serializable {
private String id;
private String name;
private String nickname;
private String phoneNum;
private String email;
//省略getter 和 setter
}
Traveller实体类:
package domain;
import java.io.Serializable;
public class Traveller implements Serializable {
private String id;
private String name;
private String sex;
private String phoneNum;
private Integer credentialsType;
private String credentialsTypeStr;
private String credentialsNum;
private Integer travellerType;
private String travellerTypeStr;
//省略getter 和 setter
}
Orders实体类:
package domain;
import org.springframework.format.annotation.DateTimeFormat;
import util.DateUtils;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
public class Orders implements Serializable {
private String id;
private String orderNum;
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm")
private Date orderTime;
private String orderTimeStr; //订单时间格式化
private int orderStatus;
private String orderStatusStr; //订单状态格式化
private int peopleCount;
private Product product;
private List<Traveller> travellers;
private Member member;
private Integer payType;
private String payTypeStr; //支付状态格式化
private String orderDesc;
//省略getter 和 setter
}
三、DAO层建立
使用Mybatis的动态代理,因此不需要自己实现DAO,因此要对DAO进行配置
IMemberDao接口:
package dao;
import domain.Member;
public interface IMemberDao {
Member findMemberById(String id);
}
IProductDao接口:
package dao;
import domain.Product;
import java.util.List;
public interface IProductDao {
//查询所有商品信息
List<Product> findAll() throws Exception;
void insert(Product product) throws Exception;
Product findById(String id);
}
ITravellerDao接口:
package dao;
import domain.Traveller;
import java.util.List;
public interface ITraveller {
/**
* 根据订单查询旅客信息
* @param id
* @return
*/
List<Traveller> findTravellerByOrderId(String id);
}
IOrderDao接口:
package dao;
import domain.Orders;
import java.util.List;
public interface IOrdersDao {
/**
* 嵌套查询全部信息
* 包括旅客信息,会员信息,产品信息
* @return
* @throws Exception
*/
List<Orders> findAll() throws Exception;
/**
* 嵌套结果查询全部
* 包括旅客信息,会员信息,产品信息
* @return
* @throws Exception
*/
List<Orders> findAll1() throws Exception;
/**
* 只查询订单
* 不包括旅客信息,会员信息,产品信息
* @return
* @throws Exception
*/
List<Orders> getAll() throws Exception;
/**
* 根据ID查询订单
* 包括旅客信息,会员信息,产品信息
* @param id
* @return
* @throws Exception
*/
Orders findById(String id) throws Exception;
}
基于XML配置Mybatis
1、配置全局配置文件:
<?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>
<!--使用typeAlias配置别名-->
<typeAliases>
<!--type指定全限定类名,alias指定别名,别名不区分大小写-->
<typeAlias type="domain.Product" alias="product"/>
<typeAlias type="domain.Orders" alias="orders"/>
<typeAlias type="domain.Member" alias="member"/>
<typeAlias type="domain.Traveller" alias="traveller"/>
</typeAliases>
<!--这个mapper必须在最下面!! 映射dao的配置文件-->
<mappers>
<mapper resource="dao/ProductMapper"/>
<mapper resource="dao/OrderMapper"/>
<mapper resource="dao/MemberMapper"/>
<mapper resource="dao/TravellerMapper"/>
</mappers>
</configuration>
这里没有配置数据源信息的原因是已经在spring中配置了
2、将mybatis工厂对象交给Spring IOC容器管理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--开启注解扫描,只需要扫描Service层的注解即可,DAO层由xml配置-->
<!-- <context:component-scan base-package="dao"/>-->
<context:component-scan base-package="service"/>
<!--Spring整合mybatis-->
<!--配置连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--注入数据库连接信息-->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ssm1?use Unicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
<!--配置sqlSession工厂对象-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--设置数据源-->
<property name="dataSource" ref="dataSource"/>
<!--映射mybatis全局配置文件-->
<property name="configLocation" value="classpath:SqlMapConfig.xml"/>
</bean>
<!-- 配置Spring的声明式事务管理 -->
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--映射mapper文件,获取生成代理Dao-->
<bean id="productMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="dao.IProductDao"/>
<property name="sqlSessionFactory" ref="factory"/>
</bean>
<bean id="orderMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="dao.IOrdersDao"/>
<property name="sqlSessionFactory" ref="factory"/>
</bean>
</beans>
3、配置每个DAO接口的Mapper文件
3.1MemberMapper
<?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="dao.IMemberDao">
<select id="findMemberById" resultType="domain.Member">
select * from member where id = #{id}
</select>
</mapper>
3.2ProductMapper
<?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="dao.IProductDao">
<select id="findAll" resultType="product">
select * from product
</select>
<insert id="insert" parameterType="product">
<selectKey keyProperty="id" keyColumn="id" resultType="java.lang.String" order="BEFORE">
select replace(uuid(),'-','')
</selectKey>
insert into product(id,productNum,productName,departureTime,cityName,productPrice,productDesc,productStatus)
values (#{id},#{productNum},#{productName},#{departureTime},#{cityName},#{productPrice},#{productDesc},#{productStatus})
</insert>
<select id="findById" resultType="product" parameterType="java.lang.String">
select * from product where id = #{id}
</select>
</mapper>
3.3TravellerMapper
<?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="dao.ITraveller">
<select id="findTravellerByOrderId" resultType="traveller" parameterType="java.lang.String">
select * from traveller where id in (select travellerId from order_traveller where #{oid} = orderId)
</select>
</mapper>
3.4OrderMapper
<?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="dao.IOrdersDao">
<!--嵌套结果查询-->
<resultMap id="orderMap" type="domain.Orders">
<id property="id" column="oid"/>
<result property="orderNum" column="orderNum"/>
<result property="orderTime" column="orderTime"/>
<result property="orderStatus" column="orderStatus"/>
<result property="peopleCount" column="peopleCount"/>
<result property="payType" column="payType"/>
<result property="orderDesc" column="orderDesc"/>
<!--association:用于映射关联查询单个对象的信息
property:要将关联查询的用户信息映射到Orders中那个属性-->
<association property="product" javaType="domain.Product">
<!-- id:关联查询的唯一标识
column:指定唯一标识信息的列
property:映射到product的哪个属性
-->
<id column="pid" property="id"/>
<result column="productNum" property="productNum"/>
<result column="productName" property="productName"/>
<result column="cityName" property="cityName"/>
<result column="departureTime" property="departureTime"/>
<result column="productPrice" property="productPrice"/>
<result column="productDesc" property="productDesc"/>
<result column="productStatus" property="productStatus"/>
</association>
<!--查询映射会员信息-->
<association property="member" javaType="domain.Member">
<id column="mid" property="id"/>
<result column="name" property="name"/>
<result column="nickname" property="nickname"/>
<result column="phoneNum" property="phoneNum"/>
<result column="email" property="email"/>
</association>
<!--根据中间表查询旅客信息-->
<!-- 关联旅客明细信息
一个订单关联查询出了多条旅客,要使用collection映射
collection:对关联查询到的多条记录映射到集合中
property:将关联查询到的多条记录映射到orders类的那个属性
ofType:指定映射的集合属性中pojo的类型
-->
<collection property="travellers" ofType="domain.Traveller">
<id column="tid" property="id"/>
<result column="name" property="name"/>
<result column="sex" property="sex"/>
<result column="phoneNum" property="phoneNum"/>
<result column="credentialsType" property="credentialsType"/>
<result column="credentialsNum" property="credentialsNum"/>
<result column="travellerType" property="travellerType"/>
</collection>
</resultMap>
<!--定义Order的ResultMap懒加载模式映射,嵌套查询-->
<resultMap id="OrderMapLazy" type="domain.Orders">
<id property="id" column="id"/>
<result property="orderNum" column="orderNum"/>
<result property="orderTime" column="orderTime"/>
<result property="orderStatus" column="orderStatus"/>
<result property="peopleCount" column="peopleCount"/>
<result property="payType" column="payType"/>
<result property="orderDesc" column="orderDesc"/>
<!--配置Order对象中product映射 ofType是类型,用全限定名或别名-->
<!--一对一查询-->
<association property="product" javaType="domain.Product" select="dao.IProductDao.findById" column="productId" fetchType="lazy"/>
<association property="member" javaType="domain.Member" select="dao.IMemberDao.findMemberById" column="memberId" fetchType="lazy"/>
<!--多对多查询,需要根据中间表来查询-->
<collection property="travellers" ofType="domain.Traveller" column="id" select="dao.ITraveller.findTravellerByOrderId" fetchType="lazy"/>
<!--如果是一对多查询,还是用colleaction标签,只不过不需要通过中间表查询-->
</resultMap>
<select id="findAll" resultMap="orderMap">
select o.id as oid,o.memberid,o.orderDesc,o.orderNum,o.orderStatus,o.orderTime,o.payType,o.peopleCount,o.productId,
p.id as pid,p.cityName,p.departureTime,p.productDesc,p.productName,p.productNum,p.productPrice,p.productStatus,
t.id as tid,t.credentialsNum,t.credentialsType,t.`name`,t.phoneNum,t.sex,t.travellerType,
m.id as mid,m.email,m.`name`,m.nickName,m.phoneNum
from orders o LEFT OUTER JOIN order_traveller ot on o.id=ot.orderId , product p,traveller t,member m
WHERE o.productId = p.id and t.id = ot.travellerId and m.id = o.memberid
</select>
<select id="findAll1" resultMap="OrderMapLazy">
select * from orders
</select>
<select id="getAll" resultType="domain.Orders">
select * from orders
</select>
<select id="findById" resultMap="OrderMapLazy" parameterType="java.lang.String">
select * from orders where id = #{id}
</select>
</mapper>