文章目錄
二钝域、整合 Mybatis 多數(shù)據(jù)源
三讽坏、整合分頁插件 PageHelper
1.搭建數(shù)據(jù)庫、項(xiàng)目配置
3.在代碼中使用PageHelper
Mybatis在整個體系中的作用是負(fù)責(zé)連接并訪問數(shù)據(jù)庫層例证。搞過開發(fā)的同學(xué)都知道路呜,沒有數(shù)據(jù)庫的項(xiàng)目一無是處,所以Mybatis的學(xué)習(xí)是很有必要的织咧。
準(zhǔn)備工作:
數(shù)據(jù)庫:在進(jìn)入正式學(xué)習(xí)前胀葱,先確保Mysql已經(jīng)在電腦上安裝好了,最好再安裝一個可視化管理工具Navicat Premium for mysql烦感。當(dāng)然巡社,你還要會mysql的語法和基本操作等。
spring boot項(xiàng)目創(chuàng)建以及一些前置知識:可以看我上一篇博客
一手趣、整合Mybatis
整合Mybatis可以基于注解晌该,也可以基于xml文件, 二者的區(qū)別:
1.搭建數(shù)據(jù)庫環(huán)境
新建一個數(shù)據(jù)庫boot_demo绿渣,然后執(zhí)行以下sql語句:
-- 創(chuàng)建表
USE `boot_demo`;
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`user_id` int(11) NOT NULL ,
`user_name` varchar(20) DEFAULT NULL,
`user_age` int(11) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE = InnoDB;
-- 插入數(shù)據(jù)
REPLACE INTO `tb_user` (`user_id`, `user_name`, `user_age`) VALUES ('100', 'test01', '100');
2.基于注解整合Mybatis
(1)創(chuàng)建項(xiàng)目
項(xiàng)目信息填寫如下:
選擇初始依賴:
完善目錄結(jié)構(gòu):
在main/java/com/tracy/mybatisdemo下依次新建 entity 朝群、dao 和 controller 文件夾。一般來說中符,應(yīng)該再創(chuàng)建一個service包姜胖,前端調(diào)用controller接口,controller調(diào)用service淀散,service再調(diào)用dao右莱,但這章為了簡化操作省去了service部分,到后面項(xiàng)目實(shí)戰(zhàn)的時候我會創(chuàng)建更完善的目錄結(jié)構(gòu)档插。
(2)具體代碼實(shí)現(xiàn)
- 實(shí)體類User:
在entity包下創(chuàng)建User類慢蜓,代碼如下:
package com.tracy.mybatisdemo.entity;
import lombok.Data;
//此注解來源于Lombok插件,運(yùn)行時會自動為類添加 Getter郭膛、Setter 晨抡、有參構(gòu)造、toString 、equals 和 hashCode 方法
@Data
public class User {
private Integer userId;
private String userName;
private Integer userAge;
}
持久層UserDao接口:
在dao包下創(chuàng)建UserDao接口:
package com.tracy.mybatisdemo.dao;
import com.tracy.mybatisdemo.entity.User;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserDao {
@Select("select user_id,user_name,user_age from tb_user")
List<User> findAll();
@Select("select user_id,user_name,user_age from tb_user where user_id = #{userId}")
User findById(Integer userId);
@Insert("insert into tb_user (user_id,user_name,user_age) values (#{userId},#{userName},#{userAge})")
Integer insert(User user);
@Update("update tb_user set user_name=#{userName},user_age=#{userAge} where user_id = #{userId}")
Integer update(User user);
@Delete("delete from tb_user where user_id=#{userId}")
Integer delete(Integer userId);
}
配置包掃描:
為了使每個dao接口都被掃描到耘柱,可以在每個dao接口上加上@Mapper注解如捅,但當(dāng)dao接口比較多的時候,推薦直接在啟動類上通過注解 @MapperScan("com.tracy.mybatisdemo.dao") 的形式掃描整個dao包:
@SpringBootApplication
@MapperScan("com.tracy.mybatisdemo.dao")
public class MybatisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisDemoApplication.class, args);
}
}
控制層UserController類:
在controller包下創(chuàng)建UserController類:
package com.tracy.mybatisdemo.controller;
import com.tracy.mybatisdemo.dao.UserDao;
import com.tracy.mybatisdemo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserDao userDao;
@GetMapping("/findAll")
public List<User> findAll(){
return userDao.findAll();
}
@GetMapping("/findById")
public User findById(Integer userId){
return userDao.findById(userId);
}
@PostMapping("/insert")
public String insert(User user){
userDao.insert(user);
return "插入成功后的數(shù)據(jù)為" + userDao.findById(user.getUserId());
}
@PutMapping("/update")
public String update(User user){
userDao.update(user);
return "更新成功后的數(shù)據(jù)為" + userDao.findById(user.getUserId());
}
@DeleteMapping("/delete")
public String delete(Integer userId){
userDao.delete(userId);
return "刪除成功的id" + userId;
}
}
添加數(shù)據(jù)庫配置:
在application.yml中添加以下配置:
# 數(shù)據(jù)源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/boot_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: 你的密碼
# Mybatis配置
# 開啟駝峰式命名規(guī)則自動轉(zhuǎn)換
mybatis:
configuration:
map-underscore-to-camel-case: true
(3)測試
測試工具我使用的是postman调煎,怎么安裝和使用可以網(wǎng)上百度一下镜遣。
- 測試 localhost:8080/user/findAll GET
- 測試 localhost:8080/user/findById GET
- 測試 localhost:8080/user/insert POST
- 測試 localhost:8080/user/update PUT
- 測試 localhost:8080/user/delete DELETE
成功!
3.基于xml整合Mybatis
基于注解的Mybatis使用只能應(yīng)付一些比較簡單的數(shù)據(jù)庫查詢語句汛蝙,雖然省事烈涮,但在一定程度上也喪失了靈活性,因此窖剑,有必要學(xué)習(xí)一下基于xml整合Mybatis。
- 首先戈稿,請先刪除UserDao接口中每個方法上的注解語句:
package com.tracy.mybatisdemo.dao;
import com.tracy.mybatisdemo.entity.User;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserDao {
List<User> findAll();
User findById(Integer userId);
Integer insert(User user);
Integer update(User user);
Integer delete(Integer userId);
}
添加xml映射文件:
在resources目錄下創(chuàng)建目錄mapper西土,仔仔mapper目錄下創(chuàng)建UserMapper.xml文件:
注意 mapper namespace=“com.tracy.mybatisdemo.dao.UserDao” 一定要與dao包下的接口對應(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.tracy.mybatisdemo.dao.UserDao">
<!--查詢所有用戶-->
<select id="findAll" resultType="user">
select * from tb_user
</select>
<!--根據(jù)id查詢單個用戶-->
<select id="findById" parameterType="int" resultType="user">
select * from tb_user where user_id = #{
userId}
</select>
<!--插入用戶-->
<insert id="insert" parameterType="user">
insert into tb_user (user_id,user_name,user_age) values (#{
userId},#{
userName},#{
userAge})
</insert>
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user set user_name = #{
userName}, user_age = #{
userAge}
where user_id = #{
userId}
</update>
<!--刪除用戶-->
<delete id="delete" parameterType="int">
delete from tb_user where user_id = #{
userId}
</delete>
</mapper>
添加Mybatis實(shí)體映射配置:
在application.yml配置文件中增加mybatis部分的配置:
# Mybatis配置
# 開啟駝峰式命名規(guī)則自動轉(zhuǎn)換
mybatis:
configuration:
map-underscore-to-camel-case: true
type-aliases-package: com.tracy.mybatisdemo.entity
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.tracy.mybatisdemo.entity表示將UserMapper.xml中的resultType與com.tracy.mybatisdemo.entity包下的實(shí)體類綁定起來鞍盗,否則UserMapper.xml中的resultType需要寫上完整的包名com.tracy.mybatisdemo.entity.user需了。
- mapper-locations: classpath:mapper/ Mapper.xml 表示將dao路徑下的各個接口與resources/mapper路徑下的各個xml文件映射起來,classpath等價于resources目錄般甲。
測試:
前面已經(jīng)演示過了肋乍,url和過程都是一模一樣的,請用postman或者別的測試工具自行測試吧敷存。
4.Mybatis的動態(tài)SQL
if 在 where 子句中做簡單的條件判斷墓造。
我們以UserMapper.xml中的update方法的實(shí)現(xiàn)為例:
原來的寫法:
當(dāng)我們調(diào)用這個接口時,必須把用戶名锚烦、用戶年齡參數(shù)都傳入觅闽,也就是說我們必須修改每一個屬性值。但是如果我們只想選擇性地修改屬性值呢涮俄,比如蛉拙,有時候我們只想修改user_name,有時候又只想修改user_age彻亲。
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user set user_name = #{
userName}, user_age = #{
userAge}
where user_id = #{
userId}
</update>
使用if進(jìn)行動態(tài)SQL綁定:
我們?yōu)槊總€參數(shù)的傳入加上一個if判斷孕锄,test="user_name!=null"表明了它的判斷條件,只有當(dāng)該參數(shù)傳入不為空時才進(jìn)行修改苞尝,這就是一種動態(tài)綁定的策略畸肆。
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user set user_id = #{
userId}
<if test="userName!=null">
user_name = #{
userName}
</if>
<if test="userAge!=null">
user_age = #{
userAge}
</if>
where user_id = #{
userId}
</update>
(2)choose
相當(dāng)于java語言中的Switch語句。
仍以update方法為例:
每個when語句都是一個條件野来,第一個條件滿足了就跳出choose語句恼除,否則判斷下一個when條件。如果所有的when條件都不滿足,就直接選擇otherwise中的條件豁辉。
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user set
<choose>
<when test="userName!=null">
user_name = #{
userName}
</when>
<when test="userAge!=null">
user_age = #{
userAge}
</when>
<otherwise>
user_id = #{
userId}
</otherwise>
</choose>
where user_id = #{
userId}
</update>
(3)trim令野、where、set
trim:
先來看看這個語句徽级,如果兩個if條件都不成立气破,那sql語句就會變成update tb_user set where user_id = #{userId},這就會導(dǎo)致語法上的錯誤:
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user set
<if test="userName!=null">
user_name = #{
userName}
</if>
<if test="userAge!=null">
user_age = #{
userAge}
</if>
where user_id = #{
userId}
</update>
使用trim語句餐抢,prefix表示整個trim語句的前綴是set现使,suffixOverrides屬性表示消除每個子句末尾可能會帶來的冗余符號(不冗余則不消除),prefixOverrides消除的是子句頭部的冗余:
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user
<trim prefix="set" suffixOverrides=",">
<if test="userName!=null">
user_name = #{
userName},
</if>
<if test="userAge!=null">
user_age = #{
userAge},
</if>
</trim>
where user_id = #{
userId}
</update>
可使用專門的set語句:
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user
<set>
<if test="userName!=null">
user_name = #{
userName}
</if>
<if test="userAge!=null">
user_age = #{
userAge}
</if>
<if test="userId!=null">
user_id = #{
userId}
</if>
</set>
where user_id = #{
userId}
</update>
可使用專門的where語句:
在where元素中至少有一個if子句成立旷痕;where元素能智能地處理 and 和 or 條件碳锈。
<!--更新用戶信息-->
<update id="update" parameterType="map">
update tb_user
<trim prefix="set" suffixOverrides=",">
<if test="userName!=null">
user_name = #{
userName},
</if>
<if test="userAge!=null">
user_age = #{
userAge},
</if>
<if test="userId!=null">
user_id = #{
userId},
</if>
</trim>
<where>
<if test="userId!=null">
user_id = #{
userId},
</if>
</where>
(4)foreach
當(dāng)需要對一個集合進(jìn)行遍歷時,foreach 元素是很有用的欺抗,尤其在 in 語句查詢時特別有用售碳。
(5)bind
二、整合 Mybatis 多數(shù)據(jù)源
如果開發(fā)人員配置了多個數(shù)據(jù)源绞呈,那么 Spring Boot 中 DataSource 和 Mybatis 的自動配置類將不會再生效贸人。
1.數(shù)據(jù)庫環(huán)境搭建
創(chuàng)建數(shù)據(jù)庫dabase1后執(zhí)行:
use `database1`;
-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`id` int(11) NOT NULL COMMENT '教師編號',
`name` varchar(50) DEFAULT NULL COMMENT '教師姓名',
`course` varchar(50) DEFAULT NULL COMMENT '所教課程',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES ('1', 'teacher01', 'C語言');
INSERT INTO `teacher` VALUES ('2', 'teacher02', 'Java');
創(chuàng)建數(shù)據(jù)庫dabase2后執(zhí)行:
USE `database2`;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL COMMENT '學(xué)號',
`name` varchar(50) DEFAULT NULL COMMENT '學(xué)生姓名',
`age` int(11) DEFAULT NULL COMMENT '年齡',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', 'student01', '20');
INSERT INTO `student` VALUES ('2', 'student02', '22');
2.實(shí)體類
在entity包下創(chuàng)建兩個實(shí)體類:
package com.tracy.mybatisdemo.entity;
import lombok.Data;
@Data
public class Teacher {
private Integer id;
private String name;
/**
* 所教課程
*/
private String course;
}
package com.tracy.mybatisdemo.entity;
import lombok.Data;
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
}
3.在application.yml配置數(shù)據(jù)源
spring:
datasource:
# datasource01
database1:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/database1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password:
# datasource01
database2:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/database2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password:
4.配置類配置數(shù)據(jù)源
在config包下創(chuàng)建DatasourceConfig類:
package com.tracy.mybatisdemo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
/**
* 根據(jù)配置文件中的屬性值配置兩個數(shù)據(jù)源datasource01和datasource02
*/
@Configuration
public class DatasourceConfig {
/**
* 實(shí)例化數(shù)據(jù)源 datasource01
*/
@Bean("datasource01")
// 設(shè)置該數(shù)據(jù)源為默認(rèn)數(shù)據(jù)源
@Primary
// 以spring.datasource.database1為前綴的屬性值自動綁定到對應(yīng)的字段中
@ConfigurationProperties(prefix = "spring.datasource.database1")
public DataSource getDatasource01() {
return DataSourceBuilder.create().build();
}
/**
* 實(shí)例化數(shù)據(jù)源 datasource02
*/
@Bean("datasource02")
@ConfigurationProperties(prefix = "spring.datasource.database2")
public DataSource getDatasource02() {
return DataSourceBuilder.create().build();
}
}
@Primary 注解指定默認(rèn)數(shù)據(jù)源,它是必要的佃声,否則會報錯艺智。
5.配置類配置 Mybatis
給每一個數(shù)據(jù)源都創(chuàng)建 SqlSessionFactory 和 SqlSession 。
數(shù)據(jù)源1:
在config包下創(chuàng)建SqlSessionConfig01類:
package com.tracy.mybatisdemo.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
/**
* 根據(jù)數(shù)據(jù)源datasource01配置sqlSessionFactory01和sqlSession01
*/
@Configuration
@MapperScan(basePackages = "com.tracy.mybatisdemo.dao.database1", sqlSessionFactoryRef = "sqlSessionFactory01")
public class SqlSessionConfig01 {
/**
* 向容器中實(shí)例化sqlSessionFactory01實(shí)例
*/
@Bean("sqlSessionFactory01")
// 設(shè)置為默認(rèn)SqlSessionFactory
@Primary
public SqlSessionFactory getSqlSessionFactory(
// 根據(jù)名稱從容器中獲取實(shí)例
@Qualifier("datasource01") DataSource dataSource) {
try {
// 實(shí)例化一個工具類圾亏,用來創(chuàng)建SqlSessionFactory
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMapperLocations(
// 設(shè)置Mybatis的xml文件位置
new PathMatchingResourcePatternResolver().getResources("classpath:mapper/database1/*.xml"));
// 返回創(chuàng)建好的sqlSessionFactory實(shí)例
return factoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
}
// 當(dāng)創(chuàng)建失敗時返回null
return null;
}
/**
* 向容器中實(shí)例化sqlSession01實(shí)例
*/
@Bean("sqlSession01")
// 設(shè)置為默認(rèn)SqlSession
@Primary
public SqlSessionTemplate getSqlSession(@Qualifier("sqlSessionFactory01") SqlSessionFactory sqlSessionFactory) {
// 利用SqlSessionFactory實(shí)例構(gòu)建一個由SpringBoot管理的線程安全的SqlSession
return new SqlSessionTemplate(sqlSessionFactory);
}
}
在config包下創(chuàng)建SqlSessionConfig02類:
package com.tracy.mybatisdemo.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
/**
* 根據(jù)數(shù)據(jù)源datasource02配置sqlSessionFactory02和sqlSession02
*/
@Configuration
@MapperScan(basePackages = "com.tracy.mybatisdemo.dao.database2", sqlSessionFactoryRef = "sqlSessionFactory02")
public class SqlSessionConfig02 {
/**
* 向容器中實(shí)例化sqlSessionFactory02實(shí)例
*/
@Bean("sqlSessionFactory02")
// 設(shè)置為默認(rèn)SqlSessionFactory
@Primary
public SqlSessionFactory getSqlSessionFactory(
// 根據(jù)名稱從容器中獲取實(shí)例
@Qualifier("datasource02") DataSource dataSource) {
try {
// 實(shí)例化一個工具類十拣,用來創(chuàng)建SqlSessionFactory
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMapperLocations(
// 設(shè)置Mybatis的xml文件位置
new PathMatchingResourcePatternResolver().getResources("classpath:mapper/database2/*.xml"));
// 返回創(chuàng)建好的sqlSessionFactory實(shí)例
return factoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
}
// 當(dāng)創(chuàng)建失敗時返回null
return null;
}
/**
* 向容器中實(shí)例化sqlSession02實(shí)例
*/
@Bean("sqlSession02")
// 設(shè)置為默認(rèn)SqlSession
@Primary
public SqlSessionTemplate getSqlSession(@Qualifier("sqlSessionFactory02") SqlSessionFactory sqlSessionFactory) {
// 利用SqlSessionFactory實(shí)例構(gòu)建一個由SpringBoot管理的線程安全的SqlSession
return new SqlSessionTemplate(sqlSessionFactory);
}
}
6.編寫 Dao接口和 SQL 映射文件
數(shù)據(jù)庫database1:
在dao包下創(chuàng)建文件夾database1,然后在database1下創(chuàng)建TeacherDao接口:
package com.tracy.mybatisdemo.dao.database1;
import com.tracy.mybatisdemo.entity.Teacher;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TeacherDao {
List<Teacher> findAll();
}
在 resources/mapper 下新建 database1 文件夾 召嘶, 在該文件夾下新建 Mapper 接口同名的映射文件即 TeacherMapper.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.tracy.mybatisdemo.dao.database1.TeacherDao">
<!--查詢所有教師信息-->
<select id="findAll" resultType="com.tracy.mybatisdemo.entity.Teacher">
select * from teacher
</select>
</mapper>
數(shù)據(jù)庫database2:
在dao包下創(chuàng)建文件夾database2父晶,然后在database2下創(chuàng)建StudentDao接口:
package com.tracy.mybatisdemo.dao.database2;
import com.tracy.mybatisdemo.entity.Student;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface StudentDao {
List<Student> findAll();
}
在 resources/mapper 下新建 database2 文件夾 , 在該文件夾下新建 Mapper 接口同名的映射文件即 StudentMapper.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.tracy.mybatisdemo.dao.database2.StudentDao">
<!--查詢所有學(xué)生信息-->
<select id="findAll" resultType="com.tracy.mybatisdemo.entity.Student">
select * from student
</select>
</mapper>
7.編寫controller
在controller包下創(chuàng)建TestController類:
package com.tracy.mybatisdemo.controller;
import com.tracy.mybatisdemo.dao.database1.TeacherDao;
import com.tracy.mybatisdemo.dao.database2.StudentDao;
import com.tracy.mybatisdemo.entity.Student;
import com.tracy.mybatisdemo.entity.Teacher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class TestController {
// 從容器中獲取teacherMapper(dataSource01操作)
@Autowired
private TeacherDao teacherDao;
// 從容器中獲取studentMapper(dataSource02操作)
@Autowired
private StudentDao studentDao;
/**
* 從database1數(shù)據(jù)庫中查詢所有教師信息
*/
@GetMapping("/teacher")
public List<Teacher> findAllTeacher() {
List<Teacher> teachers = teacherDao.findAll();
return teachers;
}
/**
* 從database2數(shù)據(jù)庫中查詢所有學(xué)生信息
*/
@GetMapping("/student")
public List<Student> findAllStudent() {
List<Student> students = studentDao.findAll();
return students;
}
}
啟動項(xiàng)目弄跌,然后在瀏覽器中訪問http://localhost:8080/teacher和http://localhost:8080/student甲喝。
三、整合分頁插件 PageHelper
Mybatis 內(nèi)部其實(shí)提供了分頁功能铛只。實(shí)現(xiàn)原理是將數(shù)據(jù)一次性查詢到內(nèi)存中埠胖,再進(jìn)行切分,從而實(shí)現(xiàn)分頁淳玩,是一種邏輯分頁方式直撤。當(dāng)數(shù)據(jù)量過大的時候,一次性讀取數(shù)據(jù)對數(shù)據(jù)庫和程序的性能都有很大的影響蜕着,因此這種方式不推薦使用谋竖。
而PageHelper 插件是一種物理分頁方式红柱。其實(shí)現(xiàn)原理是在執(zhí)行查詢的時候,獲取頁面參數(shù)蓖乘,通過攔截器在 SQL 語句中添加分頁參數(shù)生成分頁 SQL锤悄, 最終實(shí)現(xiàn)分頁查詢。
1.搭建數(shù)據(jù)庫嘉抒、項(xiàng)目配置
在mysql中創(chuàng)建數(shù)據(jù)庫page零聚,然后執(zhí)行:
USE `page`;
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`user_age` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1, 'user01', 18);
INSERT INTO `tb_user` VALUES (2, 'user02', 19);
INSERT INTO `tb_user` VALUES (3, 'user03', 18);
INSERT INTO `tb_user` VALUES (4, 'user04', 19);
INSERT INTO `tb_user` VALUES (5, 'user05', 18);
INSERT INTO `tb_user` VALUES (6, 'user06', 19);
INSERT INTO `tb_user` VALUES (7, 'user07', 18);
INSERT INTO `tb_user` VALUES (8, 'user08', 19);
INSERT INTO `tb_user` VALUES (9, 'user09', 18);
INSERT INTO `tb_user` VALUES (10, 'user10', 19);
INSERT INTO `tb_user` VALUES (11, 'user11', 18);
INSERT INTO `tb_user` VALUES (12, 'user12', 19);
INSERT INTO `tb_user` VALUES (13, 'user13', 18);
INSERT INTO `tb_user` VALUES (14, 'user14', 19);
INSERT INTO `tb_user` VALUES (15, 'user15', 18);
INSERT INTO `tb_user` VALUES (16, 'user16', 19);
INSERT INTO `tb_user` VALUES (17, 'user17', 18);
INSERT INTO `tb_user` VALUES (18, 'user18', 19);
INSERT INTO `tb_user` VALUES (19, 'user19', 18);
INSERT INTO `tb_user` VALUES (20, 'user20', 19);
在啟動類上配置包掃描:
@MapperScan("com.tracy.mybatisdemo.dao")
在application.yml中配置:
# 數(shù)據(jù)源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/page?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: 你的密碼
# Mybatis配置
# 開啟駝峰式命名規(guī)則自動轉(zhuǎn)換
mybatis:
configuration:
map-underscore-to-camel-case: true
2.添加依賴
在pom.xml中添加以下依賴:
<!--PageHelper分頁插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.3</version>
</dependency>
3.在代碼中使用PageHelper
(1)entity
在entity包下創(chuàng)建User類:
package com.tracy.mybatisdemo.entity;
import lombok.Data;
// 添加Getter,Setter些侍,toString等方法
@Data
public class User {
private Integer userId;
private String userName;
private Integer userAge;
}
在dao包下創(chuàng)建UserDao接口:
這里為了簡化使用注解綁定sql隶症。
package com.tracy.mybatisdemo.dao;
import com.tracy.mybatisdemo.entity.User;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserDao {
@Select("select user_id,user_name,user_age from tb_user")
List<User> findAll();
}
(3)controller
在controller包下創(chuàng)建UserController類:
package com.tracy.mybatisdemo.controller;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tracy.mybatisdemo.dao.UserDao;
import com.tracy.mybatisdemo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserDao userDao;
@GetMapping("/findAll")
public PageInfo<User> findAll(){
//startPage靜態(tài)方法,傳遞兩個參數(shù)(當(dāng)前頁碼岗宣,每頁查詢條數(shù))
PageHelper.startPage(1,3);
//緊跟著的第一個select 方法會被分頁
List<User> list=userDao.findAll();
PageInfo pageInfo = new PageInfo(list);
return pageInfo;
}
}
(4)測試
啟動項(xiàng)目蚂会,然后在瀏覽器訪問http://localhost:8080/user/findAll
頁面上出現(xiàn):
[{
"userId":1,"userName":"user01","userAge":18},{
"userId":2,"userName":"user02","userAge":19},{
"userId":3,"userName":"user03","userAge":18}]
成功!
(5)返回類PageInfo
此類是插件里封裝好的類狈定,可以了解一下:
public class PageInfo<T> implements Serializable {
private static final long serialVersionUID = 1L;
//當(dāng)前頁
private int pageNum;
//每頁的數(shù)量
private int pageSize;
//當(dāng)前頁的數(shù)量
private int size;
//由于startRow 和endRow 不常用颂龙,這里說個具體的用法
//可以在頁面中"顯示startRow 到endRow 共size 條數(shù)據(jù)"
//當(dāng)前頁面第一個元素在數(shù)據(jù)庫中的行號
private int startRow;
//當(dāng)前頁面最后一個元素在數(shù)據(jù)庫中的行號
private int endRow;
//總記錄數(shù)
private long total;
//總頁數(shù)
private int pages;
//結(jié)果集
private List<T> list;
//前一頁
private int prePage;
//下一頁
private int nextPage;
//是否為第一頁
private boolean isFirstPage = false;
//是否為最后一頁
private boolean isLastPage = false;
//是否有前一頁
private boolean hasPreviousPage = false;
//是否有下一頁
private boolean hasNextPage = false;
//導(dǎo)航頁碼數(shù)
private int navigatePages;
//所有導(dǎo)航頁號
private int[] navigatepageNums;
//導(dǎo)航條上的第一頁
private int navigateFirstPage;
//導(dǎo)航條上的最后一頁
private int navigateLastPage;
}
四、整合 Mybatis-Plus
Mybatis-Plus (簡稱 MP )是由國內(nèi) baomidou 組織開源的 Mybatis 的增強(qiáng)工具纽什。在原生 Mybatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡化開發(fā)躲叼,提高效率而生芦缰。
在使用過程中,MP 提供了一套通用的 Mapper 和 Service 操作枫慷,只需要繼承接口让蕾,進(jìn)行簡單的配置便可以進(jìn)行單表的 CRUD 操作。對于一些復(fù)雜的查詢或听,提供了使用數(shù)據(jù)庫字段和 POJO 屬性兩種方式來構(gòu)造條件進(jìn)行查詢探孝。此外,它自帶樂觀鎖誉裆、性能分析插件顿颅、代碼生成器和物理分頁插件等特色功能。
1.數(shù)據(jù)庫搭建足丢、配置
數(shù)據(jù)庫搭建和上一章一模一樣粱腻。
配置application.yml:
# 數(shù)據(jù)源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/page?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password:
# MyBatis-Plus的設(shè)置
# 別名包掃描路徑,為路徑下的所有類創(chuàng)建別名
mybatis-plus:
type-aliases-package: com.tracy.mybatisdemo.entity
# xml掃描路徑。然后在Mapper接口寫上自定義方法并關(guān)聯(lián)XML語句斩跌,即可實(shí)現(xiàn)手寫SQL
mapper-locations: classpath*:mapper/*.xml
# MyBatis-Plus駝峰轉(zhuǎn)換绍些,配置后不論手寫SQL還是接口方法,都能自動映射(默認(rèn)on)
configuration:
map-underscore-to-camel-case: on
# 配置生成SQL日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.添加依賴
<!--Mybatis-Plus啟動器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
3.代碼實(shí)現(xiàn)
com.tracy.mybatisdemo目錄下需要5個包:entity耀鸦、dao柬批、service、controller、config氮帐。resources目錄下需要有mapper文件夾嗅虏。
(1)entity
創(chuàng)建一個 User 實(shí)體類:
package com.tracy.mybatisdemo.entity;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.*;
// 建立實(shí)體類和數(shù)據(jù)庫表之間的對應(yīng)關(guān)系
@TableName("tb_user")
// 添加getter,setter揪漩,toString等方法
@Data
public class User {
// 用于標(biāo)識數(shù)據(jù)庫表的主鍵字段旋恼,MP 默認(rèn)數(shù)據(jù)庫表中名為 id 的字段是主鍵,如若不是奄容,需通過該注解進(jìn)行標(biāo)識冰更。
// type = IdType.AUTO 表示數(shù)據(jù)庫主鍵自增
@TableId(value = "user_id", type = IdType.AUTO)
private Integer id;
// 建立實(shí)體類字段和數(shù)據(jù)庫表屬性之間的對應(yīng)關(guān)系,當(dāng)兩者相同時可省略該注解昂勒。
@TableField
private String userName;
private Integer userAge;
}
在 MP 中蜀细,自動支持實(shí)體類字段按照駝峰轉(zhuǎn)下劃線形式的進(jìn)行轉(zhuǎn)換。
創(chuàng)建UserDao接口:
package com.tracy.mybatisdemo.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tracy.mybatisdemo.entity.User;
import org.springframework.stereotype.Repository;
@Repository
// 繼承Mybatis-Plus提供的BaseMapper戈盈,提供基礎(chǔ)的CRUD及分頁方法
public interface UserDao extends BaseMapper<User> {
}
BaseMapper:
Wrapper是一個條件構(gòu)造器奠衔,作用就是幫我們寫 SQL 語句中 where 字段后的那部分內(nèi)容。
若通用方法無法滿足業(yè)務(wù)需求塘娶,你可以在 Mapper 接口中添加自定義方法归斤,同時在 XML 中添加 SQL ,與傳統(tǒng) Mybatis 的寫法一致刁岸。
(3)service
- 接口:
在service包下創(chuàng)建UserService接口:
package com.tracy.mybatisdemo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.tracy.mybatisdemo.entity.User;
public interface UserService extends IService<User> {
}
繼承 MP 提供的 IService 接口:
為了避免和 Mapper 接口中的方法混淆脏里,Service 層中的方法命名和 Mapper 有些區(qū)別。
增加:insert → save
刪除:delete → remove
更新:udpate → update
查詢: select → get虹曙,list
- 實(shí)現(xiàn):
在service包下創(chuàng)建UserServiceImpl類:
package com.tracy.mybatisdemo.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tracy.mybatisdemo.dao.UserDao;
import com.tracy.mybatisdemo.entity.User;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService{
}
在 ServiceImpl 類中迫横,它會獲取泛型參數(shù)中的 UserDao 接口和 User 類,利用這兩者來封裝 Service 層的操作:
(4)config
配置分頁插件
在config包下新建 MybatisPlusConfig配置類:
package com.tracy.mybatisdemo.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.tracy.mybatisdemo.dao") //配置dao包掃描
public class MybatisPlusConfig {
/**
* 添加分頁插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 新的分頁插件,一緩和二緩遵循mybatis的規(guī)則
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
分頁插件配置完成后酝碳,通過如下方式便可進(jìn)行分頁:
Page<User> userPage = new Page<>();
// 設(shè)置當(dāng)前頁
userPage.setCurrent(pageNum);
// 設(shè)置頁面大小
userPage.setSize(pageSize);
// 方式1.無條件分頁查詢
Page<User> page = userService.page(userPage);
// 方式2.條件分頁查詢
Page<User> pageByWrapper = userService.page(userPage,new LambdaQueryWrapper<User>() .isNotNull(User::getUserName));
條件構(gòu)造器
針對復(fù)雜 SQL 矾踱,可以采用條件構(gòu)造器構(gòu)造條件。
QueryWapper
針對 QueryWapper 疏哗,它使用數(shù)據(jù)庫 Column 來構(gòu)造條件呛讲,在編譯期間無法檢查出錯誤。
// 構(gòu)建一個條件構(gòu)造器
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 查詢名字不為空且年齡大于18的用戶沃斤,使用數(shù)據(jù)庫字段
queryWrapper
.isNotNull("user_name")
.ge("user_age",18);
// 條件查詢
List<User> users = userService.list(queryWrapper);
LambdaQueryWrapper
針對 LambdaQueryWrapper 圣蝎,它使用 POJO 對象字段來構(gòu)造條件,可以在程序編譯的時候就能發(fā)現(xiàn)錯誤衡瓶。
// 構(gòu)建一個條件構(gòu)造器
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
// 查詢名字不為空且年齡大于18的用戶徘公,使用實(shí)體類字段
lambdaWrapper
.isNotNull(User::getUserName)
.ge(User::getUserAge,18);
// 條件查詢
List<User> users = userService.list(lambdaWrapper);
(5)controller
在controller包下創(chuàng)建:
package com.tracy.mybatisdemo.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tracy.mybatisdemo.entity.User;
import com.tracy.mybatisdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
public UserService userService;
/**
* 查詢所有-list()方法
*/
@GetMapping("/list")
public String list() {
List<User> list = userService.list();
return list.toString();
}
/**
* 根據(jù)年齡查詢用戶
*/
@GetMapping("/queryByAge")
public String queryByAge(Integer age) {
// 查詢名字不為空且年齡大于給定年齡的用戶
// 條件查詢方式1:使用QueryWrapper,使用數(shù)據(jù)庫字段
List<User> list = userService.list(new QueryWrapper<User>().isNotNull("user_name").ge("user_age", age));
// 條件查詢方式2:使用LambdaQueryWrapper,使用POJO字段
List<User> list1 = userService
.list(new LambdaQueryWrapper<User>().isNotNull(User::getUserName).ge(User::getUserAge, age));
// 條件查詢方式3:使用鏈?zhǔn)絨uery,使用數(shù)據(jù)庫字段
List<User> list2 = userService.query().isNotNull("user_name").ge("user_age", age).list();
// 條件查詢方式4:使用鏈?zhǔn)絣ambdaquery,使用POJO字段
List<User> list3 = userService.lambdaQuery().isNotNull(User::getUserName).ge(User::getUserAge, age).list();
// 只返回其中一種方式的查詢結(jié)果
return list.toString();
}
/**
* 添加用戶-save()
*/
@PostMapping("/save")
public boolean save(String userName, Integer userAge) {
User user = new User();
user.setUserName(userName);
user.setUserAge(userAge);
return userService.save(user);
}
/**
* 刪除用戶-removeById()
*/
@DeleteMapping("/remove")
public boolean remove(Integer userId) {
return userService.removeById(userId);
}
/**
* 更新用戶-updateById()
*/
@PutMapping("/update")
public boolean update(User user) {
// 注意,參數(shù)是一個對象
return userService.updateById(user);
}
/**
* 分頁查詢
*/
@GetMapping("/page")
public Page<User> page(Integer pageNum, Integer pageSize) {
Page<User> userPage = new Page<>();
// 設(shè)置當(dāng)前頁
userPage.setCurrent(pageNum);
// 設(shè)置頁面大小
userPage.setSize(pageSize);
// 方式1.無條件分頁查詢
Page<User> page = userService.page(userPage);
// 方式2.條件分頁查詢
Page<User> pageByWrapper = userService.page(userPage,
new LambdaQueryWrapper<User>().isNotNull(User::getUserName));
return page;
}
}
運(yùn)行項(xiàng)目后請自行在postman中測試每個方法哮针,不再贅述关面。