SpringBoot系列(五)Mybatis整合
目錄
- mybatis簡(jiǎn)介
- 項(xiàng)目創(chuàng)建
- entity
- dao
- service
- serviceImpl
- mapper
- controller
1. Mybatis簡(jiǎn)介
?MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射婆硬。MyBatis 避免了幾乎所有的 JDBC 代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集稠项。MyBatis 可以使用簡(jiǎn)單的 XML 或注解來(lái)配置和映射原生信息,將接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java對(duì)象)映射成數(shù)據(jù)庫(kù)中的記錄粥谬。
?換句話說(shuō),我覺(jué)得利用mybatis整合持久層要方便很多,比起以前編寫jdbc代碼操作數(shù)據(jù)庫(kù)的一些連接搂蜓,簡(jiǎn)直不要太爽。
2. 項(xiàng)目創(chuàng)建
?創(chuàng)建一個(gè)簡(jiǎn)單的具有start-web依賴的SpringBoot項(xiàng)目辽装,然后添加mybatis相關(guān)的依賴帮碰。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
?依賴下載完之后,在yml文件拾积,也可以是properties文件里面配置連接數(shù)據(jù)庫(kù)的相關(guān)配置殉挽。
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
?然后我們?cè)跀?shù)據(jù)庫(kù)mybatis下面創(chuàng)建一個(gè)student表
CREATE TABLE `student`(
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '唯一標(biāo)識(shí)id',
`name` varchar(30) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '姓名',
`age` int(3) NOT NULL COMMENT '年齡',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
完成項(xiàng)目初始配置丰涉。
3. entity 實(shí)體類代碼
/**
* (Student)實(shí)體類
*
* @author 全棧學(xué)習(xí)筆記
* @since 2020-04-14 11:39:10
*/
public class Student {
private static final long serialVersionUID = -91969758749726312L;
/**
* 唯一標(biāo)識(shí)id
*/
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 年齡
*/
private Integer age;
}
?以上省略了get,以及set方法斯碌。
4. dao層代碼
package com.example.demomybatis.dao;
import com.example.demomybatis.entity.Student;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* (Student)表數(shù)據(jù)庫(kù)訪問(wèn)層
*
* @author 全棧學(xué)習(xí)筆記
* @since 2020-04-14 11:39:18
*/
@Mapper
@Repository
public interface StudentDao {
/**
* 通過(guò)ID查詢單條數(shù)據(jù)
*
* @param id 主鍵
* @return 實(shí)例對(duì)象
*/
Student queryById(Integer id);
/**
* 查詢指定行數(shù)據(jù)
*
* @param offset 查詢起始位置
* @param limit 查詢條數(shù)
* @return 對(duì)象列表
*/
List<Student> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);
/**
* 通過(guò)實(shí)體作為篩選條件查詢
*
* @param student 實(shí)例對(duì)象
* @return 對(duì)象列表
*/
List<Student> queryAll(Student student);
/**
* 新增數(shù)據(jù)
*
* @param student 實(shí)例對(duì)象
* @return 影響行數(shù)
*/
int insert(Student student);
/**
* 修改數(shù)據(jù)
*
* @param student 實(shí)例對(duì)象
* @return 影響行數(shù)
*/
int update(Student student);
/**
* 通過(guò)主鍵刪除數(shù)據(jù)
*
* @param id 主鍵
* @return 影響行數(shù)
*/
int deleteById(Integer id);
}
?
代碼說(shuō)明:dao層屬于數(shù)據(jù)訪問(wèn)層一死,與mybatis 的xml文件相互映射,實(shí)現(xiàn)SQL語(yǔ)句的功能傻唾。
?注解說(shuō)明:在dao層的類需要加上 @Mapper的注解投慈,這個(gè)注解是mybatis提供的,標(biāo)識(shí)這個(gè)類是一個(gè)數(shù)據(jù)訪問(wèn)層的bean冠骄,并交給spring容器管理伪煤。并且可以省去之前的xml映射文件。在編譯的時(shí)候凛辣,添加了這個(gè)類也會(huì)相應(yīng)的生成這個(gè)類的實(shí)現(xiàn)類抱既。
?如果你是用的idea,在serviceImpl中使用 @Autowired注入bean的時(shí)候扁誓,idea會(huì)報(bào)錯(cuò)防泵,但是不影響運(yùn)行,報(bào)錯(cuò)是因?yàn)?@mapper不是spring提供的跋理,當(dāng)需要自動(dòng)注入這個(gè)bean的時(shí)候idea不能 預(yù)檢測(cè)到這個(gè)bean是否可以注入到容器中择克,不知道新版的idea會(huì)不會(huì)有這種問(wèn)題。如果想消除這個(gè)報(bào)錯(cuò)前普,你可以在dao層的類上面加上一個(gè) @Repository肚邢,這個(gè)注解是spring提供的,這樣就可以預(yù)檢測(cè)到mapper的bean是可以注冊(cè)到spring容器里面的拭卿。
?你會(huì)發(fā)現(xiàn)在代碼中骡湖,有的接口的參數(shù)是帶了 @Param這個(gè)注解的,有的參數(shù)是沒(méi)有這個(gè)注解的峻厚。如果你只有一個(gè)參數(shù)响蕴,這個(gè)注解可要可不要。當(dāng)你有兩個(gè)及其以上的注解時(shí)惠桃,你就需要用這個(gè)注解了浦夷,不然在對(duì)應(yīng)的xml文件,它分辨不出來(lái)這個(gè)參數(shù)是哪一個(gè)就會(huì)報(bào)錯(cuò)辜王,用這個(gè)注解的意思就是說(shuō)標(biāo)識(shí)這個(gè)參數(shù)的名稱劈狐,以便讓接受參數(shù)的一方更好的找到并利用這個(gè)值。
5. service層代碼
package com.example.demomybatis.service;
import com.example.demomybatis.entity.Student;
import java.util.List;
/**
* (Student)表服務(wù)接口
*
* @author 全棧學(xué)習(xí)筆記
* @since 2020-04-14 11:39:19
*/
public interface StudentService {
/**
* 通過(guò)ID查詢單條數(shù)據(jù)
*
* @param id 主鍵
* @return 實(shí)例對(duì)象
*/
Student queryById(Integer id);
/**
* 查詢多條數(shù)據(jù)
*
* @param offset 查詢起始位置
* @param limit 查詢條數(shù)
* @return 對(duì)象列表
*/
List<Student> queryAllByLimit(int offset, int limit);
/**
* 新增數(shù)據(jù)
*
* @param student 實(shí)例對(duì)象
* @return 實(shí)例對(duì)象
*/
Student insert(Student student);
/**
* 修改數(shù)據(jù)
*
* @param student 實(shí)例對(duì)象
* @return 實(shí)例對(duì)象
*/
Student update(Student student);
/**
* 通過(guò)主鍵刪除數(shù)據(jù)
*
* @param id 主鍵
* @return 是否成功
*/
boolean deleteById(Integer id);
}
?代碼說(shuō)明:這是服務(wù)層的接口呐馆,serviceImpl對(duì)應(yīng)服務(wù)層接口的實(shí)現(xiàn)肥缔。
6. serviceImpl層代碼
package com.example.demomybatis.service.impl;
import com.example.demomybatis.entity.Student;
import com.example.demomybatis.dao.StudentDao;
import com.example.demomybatis.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* (Student)表服務(wù)實(shí)現(xiàn)類
*
* @author 全棧學(xué)習(xí)筆記
* @since 2020-04-14 11:39:19
*/
@Service("studentService")
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
/**
* 通過(guò)ID查詢單條數(shù)據(jù)
*
* @param id 主鍵
* @return 實(shí)例對(duì)象
*/
@Override
public Student queryById(Integer id) {
return this.studentDao.queryById(id);
}
/**
* 查詢多條數(shù)據(jù)
*
* @param offset 查詢起始位置
* @param limit 查詢條數(shù)
* @return 對(duì)象列表
*/
@Override
public List<Student> queryAllByLimit(int offset, int limit) {
return this.studentDao.queryAllByLimit(offset, limit);
}
/**
* 新增數(shù)據(jù)
*
* @param student 實(shí)例對(duì)象
* @return 實(shí)例對(duì)象
*/
@Override
public Student insert(Student student) {
this.studentDao.insert(student);
return student;
}
/**
* 修改數(shù)據(jù)
*
* @param student 實(shí)例對(duì)象
* @return 實(shí)例對(duì)象
*/
@Override
public Student update(Student student) {
this.studentDao.update(student);
return this.queryById(student.getId());
}
/**
* 通過(guò)主鍵刪除數(shù)據(jù)
*
* @param id 主鍵
* @return 是否成功
*/
@Override
public boolean deleteById(Integer id) {
return this.studentDao.deleteById(id) > 0;
}
}
?代碼說(shuō)明:@Service標(biāo)識(shí)這個(gè)bean是service層的,也就是服務(wù)層汹来,并交給spring容器管理续膳。參數(shù)的value屬性是這個(gè)bean的名稱改艇,也可以不寫,默認(rèn)為類名坟岔。
?這里我們可以說(shuō)一下谒兄,@Resource與 @Autowired,前面我們?cè)?strong>serviceImpl里面需要用到dao層的方法的時(shí)候,不是直接new一個(gè)對(duì)象炮车,在哪需要就在哪new舵变,而是利用注解酣溃,實(shí)現(xiàn)自定注入裝配瘦穆,利用spring容器管理這些bean,這樣寫出來(lái)的代碼是松耦合的赊豌,類之間的耦合度更低扛或,維護(hù)性就相對(duì)提高了。
@Resource與 @Autowired是可以起到一個(gè)相同的作用碘饼。根據(jù)包名就可以看到熙兔,他們不是一個(gè)包里面的。區(qū)別如下:
- @Autowired默認(rèn)按類型裝配,默認(rèn)情況下必須要求依賴對(duì)象必須存在艾恼,如果要允許null值住涉,可以設(shè)置它的required屬性為false,如:@Autowired(required=false) 钠绍,這個(gè)注解是屬于spring的舆声,如果我們想使用名稱裝配可以結(jié)合 @Qualifier 注解進(jìn)行使用。
- @Resource默認(rèn)按照名稱進(jìn)行裝配柳爽,名稱可以通過(guò)name屬性進(jìn)行指定媳握,如果沒(méi)有指定name屬性,當(dāng)注解寫在字段上時(shí)磷脯,默認(rèn)取字段名進(jìn)行安裝名稱查找蛾找,如果注解寫在setter方法上默認(rèn)取屬性名進(jìn)行裝配。當(dāng)找不到與名稱匹配的bean時(shí)才按照類型進(jìn)行裝配赵誓。但是需要注意的是打毛,如果name屬性一旦指定挨摸,就只會(huì)按照名稱進(jìn)行裝配狈醉。這個(gè)注解屬于J2EE的。
7. mapper層代碼
?所謂的mapper層欺劳,就是xml文件绑雄,與dao層對(duì)應(yīng)的展辞。
<?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.demomybatis.dao.StudentDao">
<resultMap type="com.example.demomybatis.entity.Student" id="StudentMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="age" column="age" jdbcType="INTEGER"/>
</resultMap>
<!--查詢單個(gè)-->
<select id="queryById" resultMap="StudentMap">
select
id, name, age
from mybatis.student
where id = #{id}
</select>
<!--查詢指定行數(shù)據(jù)-->
<select id="queryAllByLimit" resultMap="StudentMap">
select
id, name, age
from mybatis.student
limit #{offset}, #{limit}
</select>
<!--通過(guò)實(shí)體作為篩選條件查詢-->
<select id="queryAll" resultMap="StudentMap">
select
id, name, age
from mybatis.student
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="name != null and name != ''">
and name = #{name}
</if>
<if test="age != null">
and age = #{age}
</if>
</where>
</select>
<!--新增所有列-->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
insert into mybatis.student(name, age)
values (#{name}, #{age})
</insert>
<!--通過(guò)主鍵修改數(shù)據(jù)-->
<update id="update">
update mybatis.student
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="age != null">
age = #{age},
</if>
</set>
where id = #{id}
</update>
<!--通過(guò)主鍵刪除-->
<delete id="deleteById">
delete from mybatis.student where id = #{id}
</delete>
</mapper>
?這里面對(duì)應(yīng)了SQL的增刪改查語(yǔ)句,然后在dao層的方法万牺,對(duì)應(yīng)了每一個(gè)SQL語(yǔ)句罗珍,這里面SQL語(yǔ)句的id洽腺,對(duì)應(yīng)dao層的每一個(gè)接口方法。
默認(rèn)的配置是檢測(cè)不到這個(gè)xml文件的覆旱,然后我們需要做以下的配置蘸朋。
我把xml文件放在resources文件夾下面的dao文件夾下面。
然后我們?cè)趛ml里面加上以下配置扣唱。
mybatis:
type-aliases-package: com.example.demomybatis.entity
mapper-locations: classpath:dao/*Mapper.xml
8. controller層代碼
?controller層的代碼我們是用來(lái)測(cè)試的藕坯,一般也是返回?cái)?shù)據(jù)給前端的地方。
package com.example.demomybatis.controller;
import com.example.demomybatis.entity.Student;
import com.example.demomybatis.service.StudentService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* (Student)表控制層
*
* @author 全棧學(xué)習(xí)筆記
* @since 2020-04-14 11:39:20
*/
@RestController
@RequestMapping("student")
public class StudentController {
/**
* 服務(wù)對(duì)象
*/
@Resource
private StudentService studentService;
/**
* 通過(guò)主鍵查詢單條數(shù)據(jù)
*
* @param id 主鍵
* @return 單條數(shù)據(jù)
*/
@GetMapping("selectOne")
public Student selectOne(Integer id) {
return this.studentService.queryById(id);
}
}
?代碼說(shuō)明:@RestController 這個(gè)注解等效于 @Controller加上 @ResponseBody,添加了這個(gè)注解就是讓這個(gè)類返回json串噪沙,這是spring內(nèi)部提供的json解析炼彪。@RequesMapping 注解是一個(gè)地址映射的注解。就是根據(jù)這個(gè)地址正歼,可以找到這個(gè)方法辐马,這個(gè)類,注解到類上局义,就相當(dāng)于方法的父類地址喜爷。
?測(cè)試一下。我們先在數(shù)據(jù)庫(kù)里面添加一條數(shù)據(jù)萄唇。
insert into student(id,name,age) VALUES(2,'全棧學(xué)習(xí)筆記',22)
?然后在瀏覽器輸入:localhost:8088/student/selectOne?id=2 就可以看到我們拿到的數(shù)據(jù)了檩帐。端口配置根據(jù)自己項(xiàng)目而定。
好了另萤,這一期的mybatis整合就到這里湃密,有興趣的可以 wx search 全棧學(xué)習(xí)筆記 ,給個(gè)關(guān)注仲墨,精彩美文每天推送到你的手中勾缭!