乐趣区

关于java:MyBatis-多条件查询动态SQL多表操作注解开发应有尽有一网打尽

起源: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

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 所过滤掉了,真是太哇塞了!

举荐一个开源收费的 Spring Boot 最全教程:

https://github.com/javastacks…

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 要用独自的标签

  • 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 把字段和属性映射封装。

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

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.1,000+ 道 Java 面试题及答案整顿(2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版