【SpringMVC】MyBatis多表操作与注解开发
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了【SpringMVC】MyBatis多表操作与注解开发相关的知识,希望对你有一定的参考价值。
参考技术A想象一下你在淘宝,在购买东西后会有个订单支付的页面,下单后用户和订单就关联起来了,同时订单有一个唯一的编号叫订单号。用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
即 order对user是一对一的,反过来,user对order是一对多的
select * ,o.id oid from orders o,user u where o.uid=u.id
这个查询结果看起来很怪,有很多个id,不着急,后面我们在进行配置文件的配置的时候可以将id忽略。
User和以前一样
测试
或者通过
<association> 标签配置user
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
select *,o.id oid from user u,orders o where u.id = o.id
打印结果
再来假设一个场景,小明是一个学生,他同时是班干部和学生会的干部,而学生会干部可以有多个学生,这样学生和学生会干部表就构成了多对多的关系
用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色
要实现这种多对多的关系,我们不仅需要role角色表,也需要一个中间表,用户和角色表之间的桥梁——用户id和角色id对应的表。
select u.*,r.*,r.id rid,u.id uid from user u left join user_role ur on u.id=ur.uid inner join role r on ur.rid=r.id
或
select * from user u,user_role ur,role r where u.id = ur.uid and ur.rid =r.id
User类添加
UserMapper接口添加
配置sqlMapperConfig.xml,给Role增加别名
这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。
我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。
修改MyBatisTest.java,将公共操作抽取出来
删除了之后,我们没有了配置文件了呀,那怎么做呢。
我们之前在sqlMapperConfig.xml里面配置了
删除了之后我们就得加载映射关系,指定接口所在的包
没有问题!说明可以运行。
实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,使用注解开发后,我们可以使用
@Results注解,@Result注解,@One注解,@Many注解
组合完成复杂关系的配置
前面我们用配置文件的方式实现了order和user的一对多查询,同样的我们也可以使用注解实现。
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
对应的sql语句:
测试
两个都可以正常运行。
我们上面的查询方式是一次查两张表,但是我们也可以通过查order表获取uid,再通过uid去查user表,这种方法怎么实现呢?
不知道你还记不记得,前面我们使用了<association>进行order和user表的一对一查询的封装,前面图中提到了@One属性,就是它的一种替代
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
可能这种方式用的比较多
对应的sql语句:
给OrderMapper.java增加一个查询方法
修改UserMapper.java
但是这种方法,其实是查到了所有的user,其中有些有orderList,原因在于这其实是一种按顺序的查询方式,先查了user表再查了order表
和
select *,o.id oid from user u,orders o where u.id = o.id 是不一样的
再来回顾一下多对多的查询
用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色
对应的sql语句:
这样子,就有个很怪的问题,注解查询每次都返回了全部的user,我不需要这么多的user啊,我只想要和role关联的那几个user,这会是一个好的方法吗。
MyBatis 多条件查询动态SQL多表操作注解开发,应有尽有,一网打尽!
点击关注公众号,Java干货及时送达
来源:iyu77.blog.csdn.net/article/details/125761737
MyBatis封装了JDBC通过Mapper代理的方式,以前繁琐的操作通过“属性与字段映射”就简单化解,MyBatis的动态SQL完美展现了DBMS的独特魅力。
一、多条件查询
基于Mybatis的多条件查询,是在Mapper代理的映射文件中写上原有的SQL,然后接口中写一个带参的方法即可,就像这样:
相比于原生的JDBC那一套,通过MyBatis确实解决了不少硬编码的问题
但是用户的查询永远是动态的操作,他可能在多个条件中选择其中少量条件进行查询,我们的SQL是死的,而用户需求对应的SQL却是活的,这样就会造成不匹配而形成语法错误
比如,根据这张表,若是要根据部分字段查出整体,我们可以写对应需求的SQL,但是我要是查询的条件变少了或者变多了呢?若用户只想通过一个条件来查询,那么在其他占位符的位置不输入于是成了null,过不了语法自然查不了,还得重新写SQL,多麻烦
这个时候MyBatis的特色就体现出来了——动态SQL。
二、动态SQL
SQL语句会随着用户的输入或者外部条件的变化而变化,则称之为动态SQL。另外,最新 MyBatis 系列面试题整理好了,大家可以在Java面试库小程序在线刷题。
1. if-where
因为采用了Mapper代理开发,我们可以通过写xml的形式来编写我们的SQL,动态SQL的特性也就在这一举动中所蕴育,在原有的Mapper文件里我们进行如下改造,让平平无奇的SQL焕然一新:
<select id="selByCondition" resultMap="rm">
select *
from mybatis
<where>
<if test="status !=null">
and STATUS=#STATUS
</if>
<if test="companyName !=null and companyName !=''">
and company_name like #companyName
</if>
<if test="bracdName !=null and bracdName !=''">
and bracd_name like #bracdName
</if>
</where>
</select>
“<where>
标签可以自动帮我们去掉and”,这样,不管查询的条件怎么变,我跟着这个逻辑流程走就不会出现SQL语法毛病而导致查询不出来的毛病啦,因为null的情况已经被if所过滤掉了,真是太哇塞了!
2. choose-when-ortherwise
对于从多个条件中选择一个的单条件查询的场景,利用分支嵌套就可以实现动态选择单条件:
在MyBatis的Mapper代理中,<choose>
相当于switch,<when>
相当于case
<select id="selByCondition2" resultMap="rm">
select *
from mybatis where
<choose>
<when test="status !=null">
STATUS=#STATUS
</when>
<when test="companyName !=null and companyName !=''">
company_name like #companyName
</when>
<when test="bracdName !=null and bracdName !=''">
bracd_name like #bracdName
</when>
<otherwise>1=1</otherwise>
</choose>
</select>
与多条件查询不同的是,SQL语句中只会有一个分支生效
当用户一个条件都不选时,可以在<otherwise>
中写上1=1
让语法成立,反之,若选择了条件则会返回正常结果。
推荐一个开源免费的 Spring Boot 最全教程:https://github.com/javastacks/spring-boot-best-practice
3. foreach
对于批量删除的场景,传统的方法是通过in关键字结合占位符来确定,就像这样
where id in (?,?,?)
但对于动态的场景,批量的数量永远是不确定的,这就导致还需要去改SQL里的占位符数量啊,又是一件麻烦事
“PS:MyBatis会将数组参数封装成一个Map集合,默认情况(K-V)array=数组。
”
下面使用了@Param
注解改变了map集合中默认的key
于是MyBatis中的<foreach>
解决了这一麻烦。
本质是通过遍历的形式,批量删除的数据是由id数组或者集合来决定,collection
属性决定了要遍历哪个数组/集合,item属性则来存放选出的元素,并把它放在占位符里,separator
属性表示分隔符
<delete id="deleteById">
delete frpm mybatis where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#id
</foreach>;
</delete>
有人会问为啥这里只有一个#id
,我的属性字段不止这一个呀?此id非彼id他是一个数组/集合。
三、多表操作
多表之间的关系有一对一,一对多,多对一,多对多,每一种都有建表的原则,以用户-订单模型为例
利用传统的方法进行多表查询无非是通过id来连接表然后封装返回结果,MyBatis中也是如此,我们在Mapper文件中写好表字段之间的映射关系,定义好类型即可,只不过这一过程有点复杂,但一次配好之后即可极大减少硬编码问题,提高效率。
1. 一对一
一个用户有一张订单
首先还是那套路,建好实体类,写好接口方法,配置Mapper文件,而多表操作的麻烦点就在于配置文件,这里通过例子细说一下
1.先把表写好
CREATE TABLE orders (
id INT PRIMARY KEY ,
ordertime VARCHAR(20) NOT NULL DEFAULT '',
total DOUBLE,
uid INT);
INSERT INTO orders VALUES(1,2020,2000,1);
INSERT INTO orders VALUES(2,2021,3000,2);
INSERT INTO orders VALUES(3,2022,4000,3);
CREATE TABLE USER (
id INT PRIMARY KEY ,
username VARCHAR(50) NOT NULL DEFAULT '',
passwords VARCHAR(50) NOT NULL DEFAULT '');
INSERT INTO USER VALUES(1,'lyy',333);
INSERT INTO USER VALUES(2,'myy',444);
INSERT INTO USER VALUES(3,'xyy',555);
2.写Mapper配置文件
在写实体类时,要把一个实体写到另一个实体的属性里面,这样才体现关联性,就比如“订单是所用户拥有的”,正因为这种关系我们才会在订单实体类里面写上private User user;
这一属性,这样根据id连接的两个实体才能完美对接!
就像这样:
通过<association>
把两张表对应的实体类连接起来,只不过是主键ID要用单独的标签
property
: 当前实体(order)中的属性名称(private User user)javaType
: 当前实体(order)中的属性的类型(User)
这两个user有着本质上的却别,就好像前者是在一个人的名字,后者正是被叫的那个人,MyBatis好像就利用了这一特性,通过标签的形式连接了两个实体
<select id="findAll" resultMap="orderMap">
SELECT *,o.id oid FROM orders o,USER u WHERE o.uid=u.id
</select>
SQL环节和原来没什么区别,同样也是通过resultMap
把字段和属性映射封装。点击关注公众号,Java干货及时送达
2.一对多
一个用户有多张订单
首先,在原有的User实体中得加上一个表示“用户有哪些订单的属性”private List<Order> orderList;
,目的是为了把订单的信息封装到用户的这个属性里,在Mapper文件中体现:
<collection property="orderList" ofType="order">
<!--封装order的数据-->
<id column="oid" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="total" property="total"></result>
</collection>
property
:集合名称,User实体中的orderlist属性ofType
:当前集合中的数据类型,就是order实体
然后就是写一对多的SQL:
<select id="findAll" resultMap="userMap">
SELECT *,o.id oid FROM USER u,orders o WHERE u.id=o.uid
</select>
总结来看,一对多相比于一对一就是在那个“一”中增添了封装“多”的属性而已,然后稍微调整一下SQL。另外,最新 MyBatis 系列面试题整理好了,大家可以在Java面试库小程序在线刷题。
3.多对多
多用户多角色
多对多的建表原则是引入一张中间表,用于维护外键,就是一张表通过中间表找到另一张表
和一对多的模型类似,先在User实体类中增添一个“用户具备哪些角色”的属性private ListroleList;其次配置Mapper文件:
<collection property="roleList" ofType="role">
<id column="roleId" property="id"></id>
<result column="roleName" property="roleName"></result>
<result column="roleDesc" property="roleDesc"></result>
</collection>
多表的连接是靠中间表,这点在Mapper文件中通过映射实现,具体是把两张外表的id(userId和roleId)在id标签中配置成同一个属性,就像这样:
<id column="userId" property="id"></id>
<id column="roleId" property="id"></id>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
SELECT * FROM USER u,user-role ur,role r WHERE u.id=ur.userId AND ur.roleId=r.id
</select>
四、注解开发
针对于简单的CRUD注解开发可以极大地提升效率,顾名思义就是把SQL写在注解里
查询(@Select):
添加(@Insert):
修改(@Update):
删除(@Delete) :
Spring Cloud 微服务最新教程!
以上是关于【SpringMVC】MyBatis多表操作与注解开发的主要内容,如果未能解决你的问题,请参考以下文章
MyBatis 多条件查询动态SQL多表操作注解开发,应有尽有,一网打尽!
MyBatis 多条件查询动态SQL多表操作注解开发,应有尽有,一网打尽!