4、SpringBoot+Mybatis多表操作以及增刪改查
Mybatis整合成功之後,接下來了解一下增刪改查的配置以及多表操作,先從增刪改查開始
為了方便後面的多表操作,現在針對資料表的配置我這裡全部在xml中配置(暫時不用註解的方式了),先看一下目前的工程結構(注意包名)
首先為了瞭解增刪改查的操作,我這裡將針對資料庫中的一個文章表進行操作,文章表結構如下:
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
對應關係如下:
附
其他類以及對映檔案的情況
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>
測試
[附]
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的名字是那個就在#{}使用那個