MyBatis封装了JDBC通过Mapper代理的方式,以前繁琐的操作通过“属性与字段映射”就简单化解,MyBatis的动态SQL完美展现了DBMS的独特魅力
一、多条件查询
基于Mybatis的多条件查询,是在Mapper代理的映射文件中写上原有的SQL,然后接口中写一个带参的方法即可,就像这样:
相比于原生的JDBC那一套,通过MyBatis确实解决了不少硬编码的问题
但是用户的查询永远是动态的操作,他可能在多个条件中选择其中少量条件进行查询,我们的SQL是死的,而用户需求对应的SQL却是活的,这样就会造成不匹配而形成语法错误
比如,根据这张表,若是要根据部分字段查出整体,我们可以写对应需求的SQL,但是我要是查询的条件变少了或者变多了呢?若用户只想通过一个条件来查询,那么在其他占位符的位置不输入于是成了null,过不了语法自然查不了,还得重新写SQL,多麻烦
这个时候MyBatis的特色就体现出来了——动态SQL
二、动态SQL
SQL语句会随着用户的输入或者外部条件的变化而变化,则称之为动态SQL
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 test="companyName !=null and companyName !=''">
and company_name like #{companyName}
<if test="bracdName !=null and bracdName !=''">
and bracd_name like #{bracdName}
</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
让语法成立,反之,若选择了条件则会返回正常结果
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要用单独的标签
这两个user有着本质上的却别,就好像前者是在一个人的名字,后者正是被叫的那个人,MyBatis好像就利用了这一特性,通过标签的形式连接了两个实体
<select id="findAll" resultMap="orderMap">
SELECT *,o.id oid FROM orders o,USER u WHERE o.uid=u.id
</select>
SQL环节和原来没什么区别,同样也是通过resultMap
把字段和属性映射封装
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>
然后就是写一对多的SQL:
<select id="findAll" resultMap="userMap">
SELECT *,o.id oid FROM USER u,orders o WHERE u.id=o.uid
</select>
总结来看,一对多相比于一对一就是在那个“一”中增添了封装“多”的属性而已,然后稍微调整一下SQL
3.多对多
多用户多角色
多对多的建表原则是引入一张中间表,用于维护外键,就是一张表通过中间表找到另一张表
和一对多的模型类似,先在User实体类中增添一个“用户具备哪些角色”的属性private List<Role> roleList;
其次配置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>
SQL环节就得用多对多的套路了
<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>
回想进行多表操作时MyBatis为我们带来了什么?他确实减少了很多硬编码,我每一次新的SQL只需要在标签里改几个属性就可以,只要理清字段与属性的映射关系,在MyBatis中进行多表操作就是一个“对号入座”
四、注解开发
针对于简单的CRUD注解开发可以极大地提升效率,顾名思义就是把SQL写在注解里
查询(@Select):
添加(@Insert):
修改(@Update):
删除(@Delete) :
1、in和exists
in是把外表和内表作hash(字典集合)连接,而exists是对外表作循环,每次循环再对内表进行查询。一直以来认为exists比in效率高的说法是不准确的,如果查询的两个表大小相当,那么用in和exists差别不大;如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in。
例如:表A(小表),表B(大表)
方式一:索引使用
1)sel...
<select id="select" resultType="com.***">
select * from A where 1=1
<if test="sss != null and sss != ''">
and sss = #{sss}
<if test="kkk != null and kkk != ''">
当用户输入的学生姓名不为空时,则只根据学生姓名进行学生信息的查询
当用户输入的学生姓名为空而学生专业不为空时,则只根据学生专业进行学生信息查询
当用户输入的学生姓名和专业都为空,则要求查询出所有学号不为空的学生信息
(2)查询出id值小于5的学生信息
简单记录下:想要修改一张表,是联合主键,也就是where后两个以上条件才能唯一确定一条数据。
如果有唯一键,那么foreach中 用in就可以解决。
现在没办法用in,不然 A in (#{})and B in (#{})感觉成笛卡尔了。
简单点就是要实现执行多条语句。对update做循环。传入参数为 List,ATest类中字段A,B为联合主键,修改C的值
<update id="update" parameterType="java.util.List">
<foreach co
Mybatis-Plus是一个基于Mybatis的增强工具,它提供了很多方便的注解来进行多表查询。其中常用的注解有:
1. @TableName:用于指定实体类对应的数据库表名。
2. @TableField:用于指定实体类属性对应的数据库字段名。
3. @TableId:用于指定实体类属性对应的数据库主键字段名。
4. @JoinTable:用于指定多表查询中的关联表和关联字段。
5. @Select:用于指定查询语句,可以使用Mybatis的动态SQL语句。
6. @Results:用于指定查询结果集的映射关系。
使用这些注解可以方便地进行多表查询,减少手写SQL的工作量。同时,Mybatis-Plus还提供了很多其他的增强功能,如自动填充、逻辑删除等,可以大大提高开发效率。
### 回答2:
MyBatis-Plus是一个开源的MyBatis框架的增强工具,可以极大地简化开发人员在使用MyBatis框架时的开发难度,其提供的注解和方法大大简化了开发的过程。当我们需要进行多表查询时,MyBatis-Plus也提供了相应的注解来帮助我们快速完成这个任务。
1. @TableJoin注解
@TableJoin注解表明了我们进行多表连接查询,其支持以下的参数:
- type:连接类型,有LEFT_JOIN、RIGHT_JOIN、INNER_JOIN、FULL_JOIN。
- entity:需要连接的实体类。
- alias:连接的实体类别名。
2. @PageableDefault注解
@PageableDefault注解可以应用于方法参数级别,指定分页参数的默认值。
3. @Select注解
@Select注解指定一个查询操作的SQL语句,其支持以下的参数:
- value: SQL语句。
- countQuery:查询总数的SQL语句 。
4. @SelectProvider注解
@SelectProvider注解指定具体的Provider类,在这个类中我们会实现查询SQL的生成逻辑。
总的来说,MyBatis-Plus提供了多种多表查询的注解来满足我们开发中的需求,这些注解可以极大的减少我们的开发成本,让我们更加专注于业务的实现。同时,MyBatis-Plus也提供了完备的文档,这些文档包含了所有需要用到的注解以及具体的使用方法,让我们更加快捷地进行开发。
### 回答3:
MyBatis-Plus是基于MyBatis的一个增强工具,其提供了很多实用的功能,其中包括多表查询注解。
多表查询注解的使用非常简单,只需要在需要查询的实体类上添加对应的注解即可,例如:
```java
@TableName(value = "user")
public class User {
@TableId(value = "id")
private Long id;
@TableField(value = "username")
private String username;
private String password;
// getter和setter省略
@TableName(value = "order")
public class Order {
@TableId(value = "id")
private Long id;
private Long userId;
private BigDecimal amount;
// getter和setter省略
假设需要查询用户信息和每个用户的订单总金额,可以通过使用@SqlSelect注解和@Join注解来实现:
```java
@SqlSelect("select u.*, sum(o.amount) as total_amount from user u left join order o on u.id = o.user_id group by u.id")
public class UserOrderVo {
@TableId(value = "id")
private Long id;
@TableField(value = "username")
private String username;
private String password;
@TableField(value = "total_amount")
private BigDecimal totalAmount;
// getter和setter省略
上述代码中,@SqlSelect注解表示自定义SQL查询语句,@Join注解表示关联查询,其中on属性表示关联条件,type属性表示关联类型,joinColumns和referencedColumns属性表示连接的两个表的关联字段。
除了@SqlSelect和@Join注解,MyBatis-Plus还提供了@SqlSeq和@SqlKey注解,用于自定义序列查询和主键生成策略。总之,MyBatis-Plus多表查询注解可以极大地简化复杂的多表查询操作,提高工作效率。