Mybatis的一对多、多对一、多对多关系详解(案例)
为什么需要关联关系?
在实际世界中,我们的单一实体不可能与其他实体毫无关系,事实上每个个体之间都有千丝万缕的联系。而在程序设计中就必须要考虑实体之间的关联,我们通过数据库表与表之间的链接来体现这种关联关系,比如外键引用等,而多对多是比较复杂的情况,也是最能体现现实业务逻辑的一种情况,数据库没办法直接体现多对多的关联关系,所以我们设计两个表的中间表来替代这种复杂的引用,这就是现今普遍的解决方案。
一对多和多对一
现在我有两个表,客户表(t_customer)和订单表(t_order),订单表保存了客户表的外键引用,通过外键可以表示一对多和多对一的映射关系,文末将会提供sql脚本代码,可以直接通过左侧索引跳转。


1) 实体类映射
package com.star.model; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor @Builder public class Customer { private Integer customerId; private String customerName; //实体层面的一对多映射 private List<Order> orders; }
package com.star.model; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor @Builder public class Order { private Integer orderId; private String orderNo; private Integer cid; //建立实体层面的映射关系 private Customer customer; }
2)mapper映射
接口代码:
package com.star.mapper; import com.star.model.Customer; import com.star.model.Order; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface CustomerMapper { int deleteByPrimaryKey(Integer customerId); int insert(Customer record); int insertSelective(Customer record); Customer selectByPrimaryKey(Integer customerId); int updateByPrimaryKeySelective(Customer record); int updateByPrimaryKey(Customer record); //通过客户id找到客户对应的订单 List<Order> queryOrderByCustomer(Customer customer); }
package com.star.mapper; import com.star.model.Customer; import com.star.model.Order; import org.springframework.stereotype.Repository; @Repository public interface OrderMapper { int deleteByPrimaryKey(Integer orderId); int insert(Order record); int insertSelective(Order record); Order selectByPrimaryKey(Integer orderId); int updateByPrimaryKeySelective(Order record); int updateByPrimaryKey(Order record); /*通过订单查询用户多对一*/ Order queryCustomerByOrder(Order order); }
xml映射:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<!--客户映射-->
<mapper namespace="com.star.mapper.CustomerMapper" >
<resultMap id="BaseResultMap" type="com.star.model.Customer" >
<constructor >
<idArg column="customer_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="customer_name" jdbcType="VARCHAR" javaType="java.lang.String" />
</constructor>
</resultMap>
<!-- 要返回的订单结果集(一对多) -->
<resultMap id="baseOneToMany" type="com.star.model.Customer" >
<!--定义主键-->
<id column="customer_id" property="customerId" javaType="java.lang.Integer"/>
<result column="customer_name" property="customerName" javaType="java.lang.String"/>
<!-- 一对多的关系 -->
<!-- property: 指的是集合属性的值, ofType:指的是集合中元素的类型 -->
<collection property="orders" ofType="com.star.model.Order">
<id column="order_id" property="orderId"/>
<result column="order_no" property="orderNo"/>
<result column="cid" property="cid"/>
</collection>
</resultMap>
<sql id="Base_Column_List" >
customer_id, customer_name
</sql>
<sql id="base_query_list">
select <include refid="Base_Column_List"/> from t_customer where 1=1
</sql>
<!--找到客户对应订单映射sql-->
<select id="queryOrderByCustomer" resultMap="baseOneToMany">
select * from t_customer ct left join t_order od on ct.customer_id=od.cid where 1=1
<if test="customerId!=null">
and customer_id = #{customerId}
</if>
</select>
<insert id="insert" parameterType="com.star.model.Customer" >
insert into t_customer (customer_id, customer_name)
values (#{customerId,jdbcType=INTEGER}, #{customerName,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.star.model.Customer" >
insert into t_customer
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="customerId != null" >
customer_id,
</if>
<if test="customerName != null" >
customer_name,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="customerId != null" >
#{customerId,jdbcType=INTEGER},
</if>
<if test="customerName != null" >
#{customerName,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.star.model.Customer" >
update t_customer
<set >
<if test="customerName != null" >
customer_name = #{customerName,jdbcType=VARCHAR},
</if>
</set>
where customer_id = #{customerId,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.star.model.Customer" >
update t_customer
set customer_name = #{customerName,jdbcType=VARCHAR}
where customer_id = #{customerId,jdbcType=INTEGER}
</update>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from t_customer
where customer_id = #{customerId,jdbcType=INTEGER}
</delete>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from t_customer
where customer_id = #{customerId,jdbcType=INTEGER}
</select>
</mapper>
<?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.star.mapper.OrderMapper">
<resultMap id="BaseResultMap" type="com.star.model.Order">
<constructor>
<idArg column="order_id" jdbcType="INTEGER" javaType="java.lang.Integer"/>
<arg column="order_no" jdbcType="VARCHAR" javaType="java.lang.String"/>
<arg column="cid" jdbcType="INTEGER" javaType="java.lang.Integer"/>
</constructor>
</resultMap>
<!--对应关系结果集(多对一)-->
<resultMap id="baseManyToOne" type="com.star.model.Order">
<id column="order_id" property="orderId"/>
<result column="order_no" property="orderNo"/>
<result column="cid" property="cid"/>
<!-- 多对一的关系 -->
<!-- property: 指的是属性的值, javaType:指的是属性的类型-->
<association property="customer" javaType="com.star.model.Customer">
<id column="customer_id" property="customerId"/>
<result column="customer_name" property="customerName"/>
</association>
</resultMap>
<sql id="Base_Column_List">
order_id, order_no, cid
</sql>
<select id="queryCustomerByOrder" resultMap="baseManyToOne">
select * from t_order od inner join t_customer cu on cu.customer_id=od.cid where 1=1
and order_id = #{orderId}
</select>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer">
select
<include refid="Base_Column_List"/>
from t_order
where order_id = #{orderId,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from t_order
where order_id = #{orderId,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.star.model.Order">
insert into t_order (order_id, order_no, cid
)
values (#{orderId,jdbcType=INTEGER}, #{orderNo,jdbcType=VARCHAR}, #{cid,jdbcType=INTEGER}
)
</insert>
<insert id="insertSelective" parameterType="com.star.model.Order">
insert into t_order
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="orderId != null">
order_id,
</if>
<if test="orderNo != null">
order_no,
</if>
<if test="cid != null">
cid,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="orderId != null">
#{orderId,jdbcType=INTEGER},
</if>
<if test="orderNo != null">
#{orderNo,jdbcType=VARCHAR},
</if>
<if test="cid != null">
#{cid,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.star.model.Order">
update t_order
<set>
<if test="orderNo != null">
order_no = #{orderNo,jdbcType=VARCHAR},
</if>
<if test="cid != null">
cid = #{cid,jdbcType=INTEGER},
</if>
</set>
where order_id = #{orderId,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.star.model.Order">
update t_order
set order_no = #{orderNo,jdbcType=VARCHAR},
cid = #{cid,jdbcType=INTEGER}
where order_id = #{orderId,jdbcType=INTEGER}
</update>
</mapper>
3)junit测试
service代码我就不贴了,注意注入mapper接口就OK。
baseTest:
package com.star.service.impl; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class BaseTest { }
测试结果:
1)测试通过客户id查询对应的订单(一对多)
2020-11-12 10:28:26.674 [main-135] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2020-11-12 10:28:27.190 [main-109] DEBUG org.apache.ibatis.io.VFS - Class not found: org.jboss.vfs.VFS 2020-11-12 10:28:27.191 [main-142] DEBUG org.apache.ibatis.io.JBoss6VFS - JBoss 6 VFS API is not available in this environment. 2020-11-12 10:28:27.192 [main-109] DEBUG org.apache.ibatis.io.VFS - Class not found: org.jboss.vfs.VirtualFile 2020-11-12 10:28:27.193 [main-70] DEBUG org.apache.ibatis.io.VFS - VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment. 2020-11-12 10:28:27.195 [main-84] DEBUG org.apache.ibatis.io.VFS - Using VFS adapter org.apache.ibatis.io.DefaultVFS 2020-11-12 10:28:29.294 [main-159] DEBUG com.star.mapper.CustomerMapper.queryOrderByCustomer - ==> Preparing: select * from t_customer ct left join t_order od on ct.customer_id=od.cid where 1=1 and customer_id = ? 2020-11-12 10:28:29.329 [main-159] DEBUG com.star.mapper.CustomerMapper.queryOrderByCustomer - ==> Parameters: 1(Integer) 2020-11-12 10:28:29.357 [main-165] TRACE com.star.mapper.CustomerMapper.queryOrderByCustomer - <== Columns: customer_id, customer_name, order_id, order_no, cid 2020-11-12 10:28:29.359 [main-165] TRACE com.star.mapper.CustomerMapper.queryOrderByCustomer - <== Row: 1, zs, 1, P01, 1 2020-11-12 10:28:29.363 [main-165] TRACE com.star.mapper.CustomerMapper.queryOrderByCustomer - <== Row: 1, zs, 2, P02, 1 2020-11-12 10:28:29.364 [main-165] TRACE com.star.mapper.CustomerMapper.queryOrderByCustomer - <== Row: 1, zs, 3, P03, 1 2020-11-12 10:28:29.365 [main-165] TRACE com.star.mapper.CustomerMapper.queryOrderByCustomer - <== Row: 1, zs, 4, P04, 1 2020-11-12 10:28:29.367 [main-165] TRACE com.star.mapper.CustomerMapper.queryOrderByCustomer - <== Row: 1, zs, 5, P05, 1 2020-11-12 10:28:29.367 [main-159] DEBUG com.star.mapper.CustomerMapper.queryOrderByCustomer - <== Total: 5 Customer(customerId=1, customerName=zs, orders=[Order(orderId=1, orderNo=P01, cid=1, customer=null), Order(orderId=2, orderNo=P02, cid=1, customer=null), Order(orderId=3, orderNo=P03, cid=1, customer=null), Order(orderId=4, orderNo=P04, cid=1, customer=null), Order(orderId=5, orderNo=P05, cid=1, customer=null)])
2)测试通过订单id查询对应的客户(多对一)
2020-11-12 10:31:38.681 [main-135] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2020-11-12 10:31:39.064 [main-109] DEBUG org.apache.ibatis.io.VFS - Class not found: org.jboss.vfs.VFS 2020-11-12 10:31:39.068 [main-142] DEBUG org.apache.ibatis.io.JBoss6VFS - JBoss 6 VFS API is not available in this environment. 2020-11-12 10:31:39.070 [main-109] DEBUG org.apache.ibatis.io.VFS - Class not found: org.jboss.vfs.VirtualFile 2020-11-12 10:31:39.072 [main-70] DEBUG org.apache.ibatis.io.VFS - VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment. 2020-11-12 10:31:39.075 [main-84] DEBUG org.apache.ibatis.io.VFS - Using VFS adapter org.apache.ibatis.io.DefaultVFS 2020-11-12 10:31:41.563 [main-159] DEBUG com.star.mapper.OrderMapper.queryCustomerByOrder - ==> Preparing: select * from t_order od inner join t_customer cu on cu.customer_id=od.cid where 1=1 and order_id = ? 2020-11-12 10:31:41.601 [main-159] DEBUG com.star.mapper.OrderMapper.queryCustomerByOrder - ==> Parameters: 1(Integer) 2020-11-12 10:31:41.625 [main-165] TRACE com.star.mapper.OrderMapper.queryCustomerByOrder - <== Columns: order_id, order_no, cid, customer_id, customer_name 2020-11-12 10:31:41.625 [main-165] TRACE com.star.mapper.OrderMapper.queryCustomerByOrder - <== Row: 1, P01, 1, 1, zs 2020-11-12 10:31:41.628 [main-159] DEBUG com.star.mapper.OrderMapper.queryCustomerByOrder - <== Total: 1 Order(orderId=1, orderNo=P01, cid=1, customer=Customer(customerId=1, customerName=zs, orders=null))
多对多
表结构,新闻和类型标签之间的多对多关系(一个标签可以对应多个新闻,一个新闻可以有多个标签):
-- 多对多 -- 主表 create table t_news ( news_id int primary key auto_increment, -- 新闻ID:主鍵 title varchar(50) not null -- 标题 ); -- 主表 create table t_category ( category_id int primary key auto_increment, -- 类别编号:主鍵 category_name varchar(50) not null -- 类别名称 ); -- 中间表 create table t_news_category ( id int primary key not null auto_increment, nid int not null, cid int not null, foreign key(nid) references t_news(news_id), foreign key(cid) references t_category(category_id) );
1)实体层
使用了lombok插件,可以快速提供无参和有参的构造函数。
package com.star.model; import lombok.*; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class News { private Integer newsId; private String title; private List<Category> categories; //后面会用到 public News(Integer newsId, String title) { this.newsId = newsId; this.title = title; } }
package com.star.model; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Category { private Integer categoryId; private String categoryName; private List<News> news; //后面会用到 public Category(Integer categoryId, String categoryName) { this.categoryId = categoryId; this.categoryName = categoryName; } }
2)mapper层
接口代码:
package com.star.mapper; import com.star.model.Category; import com.star.model.News; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface NewsMapper { int deleteByPrimaryKey(Integer newsId); int insert(News record); int insertSelective(News record); News selectByPrimaryKey(Integer newsId); int updateByPrimaryKeySelective(News record); int updateByPrimaryKey(News record); //通过新闻id查找到新闻对应的类型标签 News queryCategoryByNewId(News news); }
package com.star.mapper; import com.star.model.Category; import com.star.model.News; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface CategoryMapper { int deleteByPrimaryKey(Integer categoryId); int insert(Category record); int insertSelective(Category record); Category selectByPrimaryKey(Integer categoryId); int updateByPrimaryKeySelective(Category record); int updateByPrimaryKey(Category record); //通过类型id找到对应的新闻集合 Category queryNewsByCategoryId(Category category); }
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.star.mapper.NewsMapper"> <resultMap id="BaseResultMap" type="com.star.model.News"> <constructor> <idArg column="news_id" jdbcType="INTEGER" javaType="java.lang.Integer"/> <arg column="title" jdbcType="VARCHAR" javaType="java.lang.String"/> </constructor> </resultMap> <!--实际也可以不用单独写出来而是包含在collection标签内,但是为了好区分--> <resultMap id="base_categories" type="com.star.model.Category"> <id column="category_id" property="categoryId"/> <result column="category_name" property="categoryName"/> </resultMap> <!-- 新闻对应多个类型标签:一对多关系 --> <resultMap id="newsManyToMany" type="com.star.model.News" extends="BaseResultMap"> <!-- <id column="news_id" property="newsId"/>--> <!-- <result column="title" property="title"/>--> <collection property="categories" resultMap="base_categories"> </collection> </resultMap> <sql id="Base_Column_List"> news_id, title </sql> <!--为了方便用*代替,实际开发禁用,这里的外键引用字段都是不同的,所以可以用* 通过新闻查找类型 --> <select id="queryCategoryByNewId" resultMap="newsManyToMany"> select * from t_news nws left join t_news_category nct on nws.news_id = nct.nid left join t_category ctg on ctg.category_id = nct.cid where nws.news_id = #{newsId} </select> <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer"> select <include refid="Base_Column_List"/> from t_news where news_id = #{newsId,jdbcType=INTEGER} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer"> delete from t_news where news_id = #{newsId,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="com.star.model.News"> insert into t_news (news_id, title) values (#{newsId,jdbcType=INTEGER}, #{title,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="com.star.model.News"> insert into t_news <trim prefix="(" suffix=")" suffixOverrides=","> <if test="newsId != null"> news_id, </if> <if test="title != null"> title, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="newsId != null"> #{newsId,jdbcType=INTEGER}, </if> <if test="title != null"> #{title,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.star.model.News"> update t_news <set> <if test="title != null"> title = #{title,jdbcType=VARCHAR}, </if> </set> where news_id = #{newsId,jdbcType=INTEGER} </update> <update id="updateByPrimaryKey" parameterType="com.star.model.News"> update t_news set title = #{title,jdbcType=VARCHAR} where news_id = #{newsId,jdbcType=INTEGER} </update> </mapper>
<?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.star.mapper.CategoryMapper"> <resultMap id="BaseResultMap" type="com.star.model.Category"> <constructor> <idArg column="category_id" jdbcType="INTEGER" javaType="java.lang.Integer"/> <arg column="category_name" jdbcType="VARCHAR" javaType="java.lang.String"/> </constructor> </resultMap> <resultMap id="baseNews" type="com.star.model.News"> <id column="news_id" property="newsId"/> <result column="title" property="title"/> <collection property="categories" resultMap="BaseResultMap"/> </resultMap> <!-- 新闻对应多个类型标签:一对多关系 --> <resultMap id="categoryManyToMany" type="com.star.model.Category"> <id column="category_id" property="categoryId"/> <result column="category_name" property="categoryName"/> <collection property="news" resultMap="baseNews"> </collection> </resultMap> <sql id="Base_Column_List"> category_id, category_name </sql> <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer"> select <include refid="Base_Column_List"/> from t_category where category_id = #{categoryId,jdbcType=INTEGER} </select> <!--要注意的是主从关系,类型应该是主表,新闻是从表--> <select id="queryNewsByCategoryId" resultMap="categoryManyToMany"> select * from t_category ctg left join t_news_category nct on ctg.category_id = nct.cid left join t_news nws on nws.news_id = nct.nid where ctg.category_id = #{categoryId} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer"> delete from t_category where category_id = #{categoryId,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="com.star.model.Category"> insert into t_category (category_id, category_name) values (#{categoryId,jdbcType=INTEGER}, #{categoryName,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="com.star.model.Category"> insert into t_category <trim prefix="(" suffix=")" suffixOverrides=","> <if test="categoryId != null"> category_id, </if> <if test="categoryName != null"> category_name, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="categoryId != null"> #{categoryId,jdbcType=INTEGER}, </if> <if test="categoryName != null"> #{categoryName,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.star.model.Category"> update t_category <set> <if test="categoryName != null"> category_name = #{categoryName,jdbcType=VARCHAR}, </if> </set> where category_id = #{categoryId,jdbcType=INTEGER} </update> <update id="updateByPrimaryKey" parameterType="com.star.model.Category"> update t_category set category_name = #{categoryName,jdbcType=VARCHAR} where category_id = #{categoryId,jdbcType=INTEGER} </update> </mapper>
3)测试
同样的我就不贴Service了,测试代码:
package com.star.service.impl; import com.star.model.Category; import com.star.model.News; import com.star.service.ICategoryService; import com.star.service.INewsService; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import static org.junit.Assert.*; public class NewsServiceImplTest extends BaseTest{ @Autowired private INewsService newsService; @Autowired private ICategoryService categoryService; @Test public void queryCategoryByNewId() { //测试查询新闻对应的标签类型 System.out.println(newsService.queryCategoryByNewId(News.builder().newsId(4).build())); //测试标签类型对应的新闻 System.out.println(categoryService.queryNewsByCategoryId(Category.builder().categoryId(2).build())); } }
测试结果:
2020-11-12 10:51:57.725 [main-135] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter. 2020-11-12 10:51:58.185 [main-109] DEBUG org.apache.ibatis.io.VFS - Class not found: org.jboss.vfs.VFS 2020-11-12 10:51:58.186 [main-142] DEBUG org.apache.ibatis.io.JBoss6VFS - JBoss 6 VFS API is not available in this environment. 2020-11-12 10:51:58.189 [main-109] DEBUG org.apache.ibatis.io.VFS - Class not found: org.jboss.vfs.VirtualFile 2020-11-12 10:51:58.190 [main-70] DEBUG org.apache.ibatis.io.VFS - VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment. 2020-11-12 10:51:58.192 [main-84] DEBUG org.apache.ibatis.io.VFS - Using VFS adapter org.apache.ibatis.io.DefaultVFS 2020-11-12 10:52:00.854 [main-159] DEBUG com.star.mapper.NewsMapper.queryCategoryByNewId - ==> Preparing: select * from t_news nws left join t_news_category nct on nws.news_id = nct.nid left join t_category ctg on ctg.category_id = nct.cid where nws.news_id = ? 2020-11-12 10:52:00.892 [main-159] DEBUG com.star.mapper.NewsMapper.queryCategoryByNewId - ==> Parameters: 4(Integer) 2020-11-12 10:52:00.919 [main-165] TRACE com.star.mapper.NewsMapper.queryCategoryByNewId - <== Columns: news_id, title, id, nid, cid, category_id, category_name 2020-11-12 10:52:00.921 [main-165] TRACE com.star.mapper.NewsMapper.queryCategoryByNewId - <== Row: 4, 113, 8, 4, 1, 1, 焦点 2020-11-12 10:52:00.926 [main-165] TRACE com.star.mapper.NewsMapper.queryCategoryByNewId - <== Row: 4, 113, 9, 4, 2, 2, 国际 2020-11-12 10:52:00.927 [main-165] TRACE com.star.mapper.NewsMapper.queryCategoryByNewId - <== Row: 4, 113, 10, 4, 3, 3, 社会 2020-11-12 10:52:00.927 [main-165] TRACE com.star.mapper.NewsMapper.queryCategoryByNewId - <== Row: 4, 113, 11, 4, 4, 4, 房产 2020-11-12 10:52:00.929 [main-159] DEBUG com.star.mapper.NewsMapper.queryCategoryByNewId - <== Total: 4 News(newsId=4, title=113, categories=[Category(categoryId=1, categoryName=焦点, news=null), Category(categoryId=2, categoryName=国际, news=null), Category(categoryId=3, categoryName=社会, news=null), Category(categoryId=4, categoryName=房产, news=null)]) 2020-11-12 10:52:00.938 [main-159] DEBUG com.star.mapper.CategoryMapper.queryNewsByCategoryId - ==> Preparing: select * from t_category ctg left join t_news_category nct on ctg.category_id = nct.cid left join t_news nws on nws.news_id = nct.nid where ctg.category_id = ? 2020-11-12 10:52:00.939 [main-159] DEBUG com.star.mapper.CategoryMapper.queryNewsByCategoryId - ==> Parameters: 2(Integer) 2020-11-12 10:52:00.941 [main-165] TRACE com.star.mapper.CategoryMapper.queryNewsByCategoryId - <== Columns: category_id, category_name, id, nid, cid, news_id, title 2020-11-12 10:52:00.941 [main-165] TRACE com.star.mapper.CategoryMapper.queryNewsByCategoryId - <== Row: 2, 国际, 2, 1, 2, 1, 110 2020-11-12 10:52:00.943 [main-165] TRACE com.star.mapper.CategoryMapper.queryNewsByCategoryId - <== Row: 2, 国际, 4, 2, 2, 2, 111 2020-11-12 10:52:00.944 [main-165] TRACE com.star.mapper.CategoryMapper.queryNewsByCategoryId - <== Row: 2, 国际, 6, 3, 2, 3, 112 2020-11-12 10:52:00.945 [main-165] TRACE com.star.mapper.CategoryMapper.queryNewsByCategoryId - <== Row: 2, 国际, 9, 4, 2, 4, 113 2020-11-12 10:52:00.946 [main-159] DEBUG com.star.mapper.CategoryMapper.queryNewsByCategoryId - <== Total: 4 Category(categoryId=2, categoryName=国际, news=[News(newsId=1, title=110, categories=null), News(newsId=2, title=111, categories=null), News(newsId=3, title=112, categories=null), News(newsId=4, title=113, categories=null)])
可以看到已经获取到我们想要的数据。
数据库脚本
-- 一对多 -- 客户表(主表) create table t_customer ( customer_id int primary key not null auto_increment, customer_name varchar(50) not null ); -- 多对一 -- 订单表(从表) create table t_order ( order_id int primary key not null auto_increment, order_no varchar(50) not null unique, cid int not null, foreign key(cid) references t_customer(customer_id) ); -- 与mssql不一样,自动增长是可以赋值,也可以不赋值 insert into t_customer(customer_id,customer_name) values(1, 'zs'); insert into t_customer(customer_id,customer_name) values(2, 'ls'); insert into t_customer(customer_id,customer_name) values(3, 'ww'); insert into t_customer(customer_id,customer_name) values(4, 'xm'); insert into t_order(order_no,cid) values('P01',1); insert into t_order(order_no,cid) values('P02',1); insert into t_order(order_no,cid) values('P03',1); insert into t_order(order_no,cid) values('P04',1); insert into t_order(order_no,cid) values('P05',1); insert into t_order(order_no,cid) values('P06',2); insert into t_order(order_no,cid) values('P07',2); insert into t_order(order_no,cid) values('P08',2); insert into t_order(order_no,cid) values('P09',3); insert into t_order(order_no,cid) values('P10',3); SELECT * FROM t_customer; SELECT * FROM t_order; select * from t_customer ct left join t_order od on ct.customer_id=od.cid where 1=1; -- 多对多 -- 主表 create table t_news ( news_id int primary key auto_increment, -- 新闻ID:主鍵 title varchar(50) not null -- 标题 ); -- 主表 create table t_category ( category_id int primary key auto_increment, -- 类别编号:主鍵 category_name varchar(50) not null -- 类别名称 ); -- 中间表 create table t_news_category ( id int primary key not null auto_increment, nid int not null, cid int not null, foreign key(nid) references t_news(news_id), foreign key(cid) references t_category(category_id) ); insert into t_news(news_id,title) values(1,'110'); insert into t_news(news_id,title) values(2,'111'); insert into t_news(news_id,title) values(3,'112'); insert into t_news(news_id,title) values(4,'113'); insert into t_news(news_id,title) values(5,'114'); insert into t_news(news_id,title) values(6,'115'); insert into t_news(news_id,title) values(7,'116'); insert into t_news(news_id,title) values(8,'117'); insert into t_news(news_id,title) values(9,'118'); insert into t_category(category_id,category_name) values(1,'焦点'); insert into t_category(category_id,category_name) values(2,'国际'); insert into t_category(category_id,category_name) values(3,'社会'); insert into t_category(category_id,category_name) values(4,'房产'); insert into t_category(category_id,category_name) values(5,'财经'); insert into t_category(category_id,category_name) values(6,'娱乐'); insert into t_news_category(nid,cid) values(1,1); insert into t_news_category(nid,cid) values(1,2); insert into t_news_category(nid,cid) values(2,1); insert into t_news_category(nid,cid) values(2,2); insert into t_news_category(nid,cid) values(3,1); insert into t_news_category(nid,cid) values(3,2); insert into t_news_category(nid,cid) values(3,3); insert into t_news_category(nid,cid) values(4,1); insert into t_news_category(nid,cid) values(4,2); insert into t_news_category(nid,cid) values(4,3); insert into t_news_category(nid,cid) values(4,4); SELECT * FROM t_news; SELECT * FROM t_category; SELECT * FROM t_news_category; select * FROM t_news nws LEFT JOIN t_news_category nct ON nws.news_id = nct.nid LEFT JOIN t_category ctg ON ctg.category_id = nct.cid WHERE nws.news_id = 4;

浙公网安备 33010602011771号