4、SpringBoot+Mybatis多表操作以及增删改查

时间:2022-02-20 05:13:12

Mybatis整合成功之后,接下来了解一下增删改查的配置以及多表操作,先从增删改查开始

为了方便后面的多表操作,现在针对数据表的配置我这里全部在xml中配置(暂时不用注解的方式了),先看一下目前的工程结构(注意包名)
4、SpringBoot+Mybatis多表操作以及增删改查
首先为了了解增删改查的操作,我这里将针对数据库中的一个文章表进行操作,文章表结构如下:
4、SpringBoot+Mybatis多表操作以及增删改查
sql语句

CREATE TABLE `diary` (
`_id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`content` varchar(255) DEFAULT NULL,
`pub_time` datetime DEFAULT NULL,
`user_id` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`_id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;

编写文章操作Mapper类

package com.example.demo.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.example.demo.bean.Diary;

@Mapper
public interface DiaryMapper {

/**
* 获取文章内容
*
* @param id
* 文章id
* @return
*/

public Diary getDiaryById(@Param("id") Integer id);

/**
* 获取文章内容
*
* @param id
* 文章id
* @return
*/

public Diary getDiaryById2(@Param("id") Integer id);

/**
* 获取所有文章
*
* @return
*/

public List<Diary> getAllDiary();

/**
* 添加文章
*/

public Integer addDiary(Diary d);

/**
* 更新文章
*
* @param d
*/

public Integer updateDiary(Diary d);

/**
* 删除文章
* @param id
* @return
*/

public Integer deleteDiary(@Param("id") Integer id);

}

查询部分比较复杂,可以后面再看,先搞定简单的

编写结果映射文件(xml)

在src/main/resource/com/example/demo/mapper/下创建映射文件,这里我直接用操作接口类名首字母小写来作为文件名,diaryMapper .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.example.demo.mapper.DiaryMapper">

<update id="updateDiary" parameterType="com.example.demo.bean.Diary">
update diary set
title=#{title},content=#{content},pub_time=#{pubTime}
where _id=#{id}
</update>

<delete id="deleteDiary" parameterType="int">
delete from diary where
_id=#{id}
</delete>
<insert id="addDiary" useGeneratedKeys="true" keyProperty="id"
parameterType="com.example.demo.bean.Diary">

insert into diary(title,content,pub_time,user_id)
values(#{title},#{content},#{pubTime},#{userId})
</insert>
...先省略查询部分...
</mapper>

首先mapper其实描述的是一个操作接口,如这里就是描述着com.example.demo.mapper.DiaryMapper这个接口,namespace属性直接用包名.类名表示即可

namespace="com.example.demo.mapper.DiaryMapper"

下面其他Mapper接口也一样,分别对应一个mapper xml文件即可

这里标签都比较简单,从标签名就可以看出来具体的操作了(这不是废话嘛…),接着主要看一下标签内的属性:

id:可以理解为对应Java文件中的方法名
parameterType:可以理解为该方法的参数类型,无参数可以不写

标签括起来的就是sql语句,其中需要引用方法参数时可以使用#{参数名}
来引用,如Java中的方法为:

public Integer deleteDiary(@Param("id") Integer mId);

这里用@Param(“id”)标注了参数mId,因此如果要在sql中引用mId的值则可以直接用#{id}

delete from diary where _id=#{id}

这里插入数据的方法是Diary文章对象:

public Integer addDiary(Diary d);

默认情况下,参数是对象时在写sql语句时可以直接用对象的属性作为参数

insert into diary(title,content,pub_time,user_id) values(#{title},#{content},#{pubTime},#{userId})

注意:增删改的结果可以返回一个int类型,一般操作成功会大于0,否则会返回0

运用

package com.example.demo.controller;

import java.sql.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.example.demo.bean.Diary;
import com.example.demo.bean.User;
import com.example.demo.mapper.DiaryMapper;

@RestController
public class DiaryMappingController {
@Autowired
DiaryMapper diaryMapper;

...省略其他...

@RequestMapping("/add_diary")
public String addDiary(String title, String content, int userId) {
Diary d = new Diary(title,content,new Date(System.currentTimeMillis()),userId);
int row = diaryMapper.addDiary(d);
if (row > 0) {
return "success";
} else {
return "fail";
}
}
}

关于查询以及多表查询

为了体现多表查询的环境,这里在数据库中新增了用户表、标签表、文章标签对应表

--用户表(一个文章由一个用户发布)
CREATE TABLE `users` (
`_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`psw` varchar(255) NOT NULL,
`sex` varchar(2) DEFAULT NULL,
`sign` varchar(255) DEFAULT NULL,
`photo` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT '0',
PRIMARY KEY (`_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;


--标签表
CREATE TABLE `tags` (
`_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`creator` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


--文章标签对应表(一个文章可以有多个标签)
CREATE TABLE `diary_tags` (
`diary_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
`extras` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

同时针对这些数据在Java中也定义了相应的类型来接收

User.java描述用户类型,表示文章发布者信息

package com.example.demo.bean;

public class User {
private int id;
private String name;
private String sex;
private String sign;
private String photo;
private int age;
...省略getter/setter...
}

Tag.java标签类型,表示文章所在的标签

package com.example.demo.bean;

/**
* 标签
* @author Administrator
*
*/

public class Tag {
private int id;
private String name;
...省略getter/setter...
}

Diary.java文章类型,描述了文章信息以及作者、所处的标签等

package com.example.demo.bean;

import java.sql.Date;
import java.util.List;

public class Diary {
private int id;
private String title;
private String content;
private Date pubTime;
private int userId;
private User user; //作者信息
private List<Tag> tags; //所处的标签,一个文章可以属于不同的标签
...省略getter/setter...
public Diary(String title, String content, Date pubTime, int userId) {
this.title = title;
this.content = content;
this.pubTime = pubTime;
this.userId = userId;
}
public Diary() {
}
}

针对上面这个复杂的结构(文章中有一个作者信息,同时有多个标签信息),如果要找出一个文章的完整信息,那么需要通过文章表中的user_id字段到users表中查询用户信息,同时还需要通过文章表的id到diary_tags表中找到所关联的标签(找到标签id)然后再从tags表中获取标签列表。因此查询的mapper配置如下

...省略前面的增删改的配置...
<resultMap type="com.example.demo.bean.Diary" id="DiaryMap">
<id property="id" column="_id" />
<result property="title" column="title" />
<result property="content" column="content" />
<result property="pubTime" column="pub_time" javaType="java.sql.Date" />
<association property="user" column="user_id"
javaType="com.example.demo.bean.User">
<id property="id" column="uId" />
<result property="name" column="name" />
<result property="sex" column="sex" />
<result property="sign" column="sign" />
<result property="photo" column="photo" />
<result property="age" column="age" />
</association>
<collection property="tags" ofType="com.example.demo.bean.Tags"
column="_id" select="com.example.demo.mapper.TagMapper.getTagsByDiaryId">
</collection>
</resultMap>

<select id="getDiaryById" parameterType="int" resultMap="DiaryMap">
select
d._id,d.title,d.content,d.pub_time,d.user_id,u._id as
uId,u.name,u.sex,u.sign,u.photo,u.age
from diary d left join users u on
d.user_id=u._id where d._id=#{id}
</select>

<select id="getAllDiary" resultMap="DiaryMap">
select
d._id,d.title,d.content,d.pub_time,d.user_id,u._id as
uId,u.name,u.sex,u.sign,u.photo,u.age
from diary d left join users u on
d.user_id=u._id
</select>

<resultMap type="com.example.demo.bean.Diary" id="DiaryMap2">
<id property="id" column="_id" />
<result property="title" column="title" />
<result property="content" column="content" />
<result property="pubTime" column="pub_time" javaType="java.sql.Date" />
<result property="userId" column="user_id" />
<association property="user" column="user_id"
javaType="com.example.demo.bean.User" select="com.example.demo.mapper.UserMapper.getUserById">
</association>
<collection property="tags" ofType="com.example.demo.bean.Tags"
column="_id" select="com.example.demo.mapper.TagMapper.getTagsByDiaryId">
</collection>
</resultMap>

<select id="getDiaryById2" parameterType="int" resultMap="DiaryMap2">
select
* from diary where _id=#{id}
</select>

resultMap标签配置的是查询结果,type表示结果返回类型,id则表示该结果处理的一个独一无二名称而已
resultMap中的属性

id标签:主键映射
result标签:普通属性的映射
association标签:关联其他查询一个对象的映射,如当前环境的作者信息
collection标签:关联其他查询的集合,如当前环境的标签列表
标签上的属性
property表示Java对象中的属性名
column表示对应的查询结果中数据库字段名
select表示该结果的其他查询方法(子查询)

映射结果的关联是有select标签中的resultMap属性来关联的,该属性值对应一个resultMap标签的id
对应关系如下:
4、SpringBoot+Mybatis多表操作以及增删改查

其他类以及映射文件的情况
UserMapper.java处理用户表的用户信息操作类,这里练习的时候也可以全部写到同一个类中,现在分开主要是为了后面新增方法的需要

package com.example.demo.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.example.demo.bean.User;

@Mapper
public interface UserMapper {

/**
* 根据id获取用户信息
* @param id
* @return
*/

public User getUserById(@Param("id") int id);
}

userMapper.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.example.demo.mapper.UserMapper">
<resultMap type="com.example.demo.bean.User" id="UserMap">
<id property="id" column="_id" />
<result property="name" column="name" />
<result property="sex" column="sex" />
<result property="sign" column="sign" />
<result property="photo" column="photo" />
<result property="age" column="age" />
</resultMap>
<select id="getUserById" parameterType="int" resultMap="UserMap">
select * from users where _id=#{id}
</select>
</mapper>

TagMapper.java

package com.example.demo.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.example.demo.bean.Tag;

@Mapper
public interface TagMapper {

/**
* 根据文章id获取标签列表
* @param diaryId
* @return
*/

public List<Tag> getTagsByDiaryId(@Param("d_id") int diaryId);
}

tagMapper.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.example.demo.mapper.TagMapper">

<resultMap type="com.example.demo.bean.Tag" id="TagMap">
<id property="id" column="_id" />
<result property="name" column="name" />
</resultMap>

<select id="getTagsByDiaryId" parameterType="int" resultMap="TagMap">
select * from tags where _id in (select tag_id from diary_tags where diary_id=#{d_id})
</select>
</mapper>

测试

4、SpringBoot+Mybatis多表操作以及增删改查

源码:https://github.com/huajianzh/spring/tree/master/springdemo

[附]

MyBatis传入多个参数的问题

针对多个参数的情况,parameterType可以不用指定

1、可以直接使用#{参数下标}的方式访问

public List<XXXBean> getXXXBeanList(String xxId, String xxCode);  

<select id="getXXXBeanList" resultType="XXBean">
  select t.* from tableName where id = #{0} and name = #{1}
</select>

2、之际在方法参数中使用@Parm声明各个参数的别名

public AddrInfo getAddrInfo(@Param("corpId")int corpId, @Param("addrId")int addrId);

<select id="getAddrInfo" resultMap="com.xxx.xxx.AddrInfo">
SELECT * FROM addr_info
    where addr_id=#{addrId} and corp_id=#{corpId}
</select>

3、封装List

public List<XXXBean> getXXXBeanList(List<String> list);  

<select id="getXXXBeanList" resultType="XXBean">
  select 字段... from XXX where id in
  <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
    #{item}
  </foreach>
</select>

foreach 最后的效果是select 字段... from XXX where id in ('1','2','3','4')

4、使用Map携带多个参数

public List<XXXBean> getXXXBeanList(HashMap map);  

<select id="getXXXBeanList" parameterType="hashmap" resultType="XXBean">
  select 字段... from XXX where id=#{xxId} code = #{xxCode}
</select>

其中hashmap是mybatis自己配置好的直接使用就行。map中key的名字是那个就在#{}使用那个