一.MybatisPlus的快速入门
(1)开发环境
IDEA:IntelliJ IDEA 2021.3.3
JDK:14.0.2
MySql:
SpringBoot:2.6.7
MyBatis_Plus:3.5.1
(2)创建数据库的表和对应的实体类
创建表和插入数据的sql语句
CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
USE `mybatis_plus`;
CREATE TABLE `user` (
`id` BIGINT(20) NOT NULL COMMENT '主键ID',
`name` VARCHAR(30) DEFAULT NULL COMMENT '姓名',
`age` INT(11) DEFAULT NULL COMMENT '年龄',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
创建实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private long id;
private String name;
private Integer age;
private String email;
}
(3)创建SpringBoot工程
导入依赖
<dependencies>
<!--mybatis-plus场景启动器依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--lombok依赖用于简化实体类开发,注意这个lombok是需要下载插件的-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--数据库驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--默认添加的依赖:spring-boot场景启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--默认添加的依赖:spring-boot测试功能的场景启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置SpringBoot的application.yml
spring:
#配置数据源信息
datasource:
#配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
#配置链接数据库的各个信息
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false
username: root
password: root
注意:
1.驱动类driver-class-name:
spring boot 2.0(内置jdbc5驱动),驱动类使用:
driver-class-name: com.mysql.jdbc.Driver
spring boot 2.1及以上(内置jdbc8驱动),驱动类使用:driver-class-name: com.mysql.cj.jdbc.Driver
否则运行测试用例的时候会有 WARN 信息
2.连接地址url MySQL5.7版本的url:
jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
MySQL8.0版本的url:jdbc:mysql://localhost:3306/mybatis_plus?
serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more
写mapper接口继承BaseMapper,并且启动类扫描
@Component
public interface UserMapper extends BaseMapper<User> {
}
@SpringBootApplication
@MapperScan("com.example.mybatisplus_demo.mapper")//扫描mapper接口所在的包
public class MyBatisPlusDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyBatisPlusDemoApplication.class, args);
}
}
(4)测试
@SpringBootTest
class MyBatisPlusDemoApplicationTests {
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
System.out.println(users);
}
}
(5)[拓展]添加日志功能
其实只需要在配置文件中加上配置信息就行
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
二.增删改查功能的实现
(1)Dao层基础的单表CRUD:
@Autowired
UserMapper userMapper;
@Test//查询记录
void test4() {
/*共10种,先测试3种,带Wrapper条件的先不测*/
User user = userMapper.selectById(1L);//第一种
System.out.println(user);
List<Long> ids = Arrays.asList(3L, 4L);//第二种,SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )
List<User> users = userMapper.selectBatchIds(ids);
System.out.println(users);
Map<String,Object> map=new HashMap<>();map.put("name","萧萧");map.put("age",2000);
userMapper.selectByMap(map);//第三种
}
@Test//修改记录
void test3() {
/*共两种,先测试一种,带Wrapper条件的先不测*/
User user = new User(1L,"萧萧", 2000, "xiaoxiao@123.com");
userMapper.updateById(user);
}
@Test//删除记录
void test2() {
/*共五种,先测试四种,带Wrapper条件的先不测*/
userMapper.deleteById(1);//第一种
userMapper.deleteById(new User(2L));//第二种
Map<String,Object> map=new HashMap<>();map.put("name","萧萧");map.put("age",2000);
userMapper.deleteByMap(map);//第三种
List<Long> ids = Arrays.asList(3L, 4L);
userMapper.deleteBatchIds(ids);//第四种:DELETE FROM user WHERE id IN ( ? , ? )
}
@Test//添加记录
void test1() {
User user = new User("萧萧", 2000, "xiaoxiao@123.com");
int result = userMapper.insert(user);//会增加一条记录,并且自动生成id,将id赋值给该对象的id属性
System.out.println(result);
System.out.println("id"+user.getId());//id是雪花算法自动生成的,
}
(2)自定义功能
这里的步骤就跟Mybatis中一样了,但是有几个点要注意。首先mapper映射文件有默认的路径(也就是在resources/mapper下写映射文件),可以在yml配置文件中进行自己配置。
@Test//自定义
void test5() {
Map<String, Object> stringObjectMap = userMapper.selectMapById(1L);
System.out.println(stringObjectMap);
}
<select id="selectMapById" resultType="map">
select * from user where id=#{id}
</select>
自己配置除了要在配置文件中加上面的代码,还要在pom.xml中加上:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
(3)Service层封装的单表CRUD:
继承和实现体系
在IService<T>接口中封装了CRUD的方法,而ServiceImpl<M extends BaseMapper<T>, T> implements IService<T>是它的实现类。
如果我们想要使用这个,我们需要新建一个接口UserService去继承IService<T>接口,同时UserService的实现类UserServiceImpl还要继承ServiceImpl,省得重写方法。
//继承接口
public interface UserService extends IService<User> {
}
//实现自定义接口
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}
简单的测试
@Autowired
UserServiceImpl userService;
@Test//简简单单,只测试两个方法
void test() {
//查询总记录数
long count = userService.count();
System.out.println(count);
//批量添加
List<User> list =new ArrayList<>();
for(int i=1;i<=5;i++){
User user = new User();
user.setName("xiaoxiao"+i);
user.setAge(20+i);
list.add(user);
}
boolean b = userService.saveBatch(list);
System.out.println(b);
}
(4)条件构造器Wrapper
1.QueryWrapper
简单的删改查
@Test
public void test(){
//删除,查询都要用QueryWrapper
QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>();
userQueryWrapper.eq("user_name","萧萧");//等于
userQueryWrapper.ge("uid",1); //ge是大于等于,le小于等于
userQueryWrapper.le("uid",4);
userQueryWrapper.isNotNull("user_name");
//Asc是升序,Desc是降序
//先按照age升序排序,相同的话就按照uid的降序排序
userQueryWrapper.orderByAsc("age").orderByDesc("uid");
List<User> users = userMapper.selectList(userQueryWrapper);
System.out.println(users);
}
@Test
public void test2(){//修改操作
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
//ge是>= le是<= gt是> lt是<
//把年纪大于等于12并且名字中带a的人 或者 email是空的人进行修改
userQueryWrapper.ge("age",12)
.like("user_name","a")
.or()
.isNull("email");
User user = new User();
user.setName("小明");
user.setEmail("xiaoming@123.com");
//UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (age >= ? AND user_name LIKE ? OR email IS NULL)
userMapper.update(user,userQueryWrapper);
}
条件优先级
@Test
public void test3(){//修改操作。优先级
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
//ge是>= le是<= gt是> lt是<
//把名字中带a的人并且(年纪大于等于12或者email是空)的人进行修改
//lambda中的条件优先执行
userQueryWrapper
.like("user_name","明")
.and(i->i.ge("age",12).or().isNull("email"));
User user = new User();
user.setName("小红");
user.setEmail("xiaoming@123.com");
//UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age >= ? OR email IS NULL))
userMapper.update(user,userQueryWrapper);
}
组装select语句:也就是只查询自己想要的字段。
@Test//组装select字句
public void test4(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.select("uid","user_name");
List<Map<String, Object>> maps = userMapper.selectMaps(userQueryWrapper);
System.out.println(maps);
}
组装子查询
@Test//组装select字句
public void test4(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.select("uid","user_name");
List<Map<String, Object>> maps = userMapper.selectMaps(userQueryWrapper);
System.out.println(maps);
}
2. UpdateWrapper
简单的修改操作
@Test//UpdateWrapper
public void test6(){
//把名字中带a的人并且(年纪大于等于12或者email是空)的人进行修改
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper.like("user_name","红")
.and(i->i.ge("age",12).or().isNull("email"))
.set("user_name","小黑").set("email","xiaohei@guigu.com");
userMapper.update(null,userUpdateWrapper);
}
模拟开发环境中组装条件的情况
@Test
public void test7(){
String username=" ";
Integer ageBegin=20;
Integer ageEnd=50;
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(username)){
userQueryWrapper.like("username",username);
}
if(ageBegin!=null){
userQueryWrapper.ge("age",ageBegin);
}
if(ageEnd!=null){
userQueryWrapper.le("age",ageEnd);
}
List<User> users = userMapper.selectList(userQueryWrapper);
System.out.println(users);
}
上述的情况还有另一种解决的方法
@Test
public void test8(){
String username=" ";
Integer ageBegin=20;
Integer ageEnd=50;
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper
.like(StringUtils.isNotBlank(username),"username",username)
.ge(ageBegin!=null,"age",ageBegin)
.le(ageEnd!=null,"age",ageEnd);
//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)
List<User> users = userMapper.selectList(userQueryWrapper);
System.out.println(users);
}
3.LambdaWrapper
@Test//LambdaQueryWrapper
public void test9(){
String username=" ";
Integer ageBegin=20;
Integer ageEnd=50;
LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
userLambdaQueryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
.ge(ageBegin!=null,User::getAge,ageBegin)
.le(ageEnd!=null,User::getAge,ageEnd);
//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (age >= ? AND age <= ?)
List<User> users = userMapper.selectList(userLambdaQueryWrapper);
System.out.println(users);
}
@Test//LambdaUpdateWrapper
public void test10(){
String username=" ";
Integer ageBegin=21;
Integer ageEnd=21;
LambdaUpdateWrapper<User> objectLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
objectLambdaUpdateWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
.ge(ageBegin!=null,User::getAge,ageBegin)
.le(ageEnd!=null,User::getAge,ageEnd);
//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (age >= ? AND age <= ?)
List<User> users = userMapper.selectList(objectLambdaUpdateWrapper);
System.out.println(users);
}
三.常用注解
(1)@TableName
聪明的小伙伴已经发现了,要是表名和实体类名不一样就会报错,有两个办法可以解决这个问题:
1.在类名上面加上注解@TableName
@TableName("t_user")//这里面的是数据库中的表名
public class User {
private Long id;
private String name;
private Integer age;
private String email;
public User(String name, Integer age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public User(Long id) {
this.id = id;
}
}
2.在配置文件中进行全局配置
(2)@TableId
Mybatis_plus会默然把类中的id作为主键,但是我们有是有为了数据库中字段名和实体类的属性相匹配,就会出现uid、tid等属性名。如果不给对象的uid属性赋值,就把这个对象插入进数据库里,Mybatis_plus不会对uid属性自动赋值,但是uid是数据库中的主键,就会报错。
在uid属性上面加该注解
public class User {
@TableId//将属性对应的数据库中字段定义为主键
private Long uid;
}
该注解的两个属性
如果数据库中是uid,类中属性名是id,要匹配呀!就要用到该注解的value属性
public class User {
@TableId(value="uid")//value属性表示,id这个属性对应数据库中的uid字段
private Long id;
}
主键的生成策略是可以改变的!可以使用该注解,当然也可以使用全局配置来设置生成策略:
public class User {
//value属性表示,id这个属性对应数据库中的uid字段
//type属性用于设置id的生成策略,ASSIGN_ID是雪花算法,AUTO是自增
//type= IdType.AUTO使用该type的前提是数据库中要设置成自增,不然会报错
//如果手动给id赋值的话是不会调用该雪花算法的
@TableId(value="uid",type= IdType.AUTO)
private Long id;
}
(3)TableField
当主键之外的字段名和属性名不匹配的时候,会用到该注解。比如,字段名是user_name,属性名是username。注意如果这里属性名是userName,不会出问题,因为有默认的驼峰映射关系。
@TableField("user_name")//这里面的字符串就是字段名
private String name;
(4)TableLogic
这个是用于逻辑删除。首先在数据库中添加is_deleted,默认值设置为0表示未删除,1表示已经删除。
@TableLogic
private Integer isDeleted;
四.其他功能
(1)分页插件
需要一个配置类去配置:
@Configuration
@MapperScan("com.example.mybatisplus_demo.mapper")//扫描mapper接口所在的包
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
测试代码如下:
@SpringBootTest
public class plugins_test {
@Autowired
UserMapper userMapper;
@Test
public void testPage(){
Page<User> userPage = new Page<>(1,3);//访问第一页,每页显示三条数据
userMapper.selectPage(userPage,null);//进行分页查询
System.out.println(userPage);
//分页相关数据获取
System.out.println(userPage.getRecords());//获取查到的某一页记录
System.out.println(userPage.getPages());//获取总记录数
System.out.println(userPage.getTotal());//获取总页数
System.out.println(userPage.hasNext());//是否有下一个
System.out.println(userPage.hasPrevious());//是否有上一个
}
}
自定义分页功能:
//通过年龄来查询数据
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
<!--Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);-->
<select id="selectPageVo" resultType="User">
select * from t_user where age>#{age}
</select>
@Test//自定义分页功能测试代码
public void testPageVo(){
Page<User> userPage = new Page<>(1,3);//访问第一页,每页显示三条数据
userMapper.selectPageVo(userPage,22);//进行分页查询
//select * from t_user where age>? LIMIT ?
System.out.println(userPage);
}
(2)乐观锁插件
场景:两个人对售价100的商品进行修改,小李要加50小王要减30,最后期望的价格应该是120。但是如果不加锁:两个人同时取出数据100,小李加了50元,将150元的价格存到了数据库。这个时候,小王对他拿到的数据进行修改,得到70覆盖掉了150元。这就出现了问题
乐观锁和悲观锁:乐观锁的话小王在保存数据之前会查看价格是否被修改过了,若果被改过那么就取出被修改过的价格,然后再进行修改,这样就会使结果正确。如果是悲观锁,小李取出数据之后,小王只能在小李才做完之后才能够对价格进行操作,这样也能保证价格的正常。
乐观锁实现
创建个表,然后添加数据:
添加实体类:
@Data
public class Product {
private Long id;
private String name;
private Integer price;
private Integer version;
}
添加mapper并测试
@Autowired
ProductMapper productMapper;
@Test//现在是不是使用乐观锁,原本价格是500,本次操作后价格是470
public void test2(){
//小李查询商品价格
Product product1 = productMapper.selectById(1);
System.out.println("小李查到的价格是:"+product1.getPrice());
//小王查到的商品价格
Product product2 = productMapper.selectById(1);
System.out.println("小王查到的价格是:"+product2.getPrice());
//小李修改价格
product1.setPrice(product1.getPrice()+50);
productMapper.updateById(product1);
//小李王修改价格
product2.setPrice(product2.getPrice()-30);
productMapper.updateById(product2);
//老板来查数据
Product product3 = productMapper.selectById(1);
System.out.println(product3.getPrice());
}
添加乐观锁:
//在实体类的属性上添加注解
@Version//标志着这是一个乐观锁版本号的属性
private Integer version;
//在配置类里面添加乐观锁插件
@Configuration
@MapperScan("com.example.mybatisplus_demo.mapper")//扫描mapper接口所在的包
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//添加分页插件
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//添加乐观锁插件
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
@Test//现在是使用乐观锁,原本价格是100,本次操作后价格是120
public void test2(){
//小李查询商品价格
Product product1 = productMapper.selectById(1);
System.out.println("小李查到的价格是:"+product1.getPrice());
//小王查到的商品价格
Product product2 = productMapper.selectById(1);
System.out.println("小王查到的价格是:"+product2.getPrice());
//小李修改价格
product1.setPrice(product1.getPrice()+50);
productMapper.updateById(product1);
//小李王修改价格
product2.setPrice(product2.getPrice()-30);
int result = productMapper.updateById(product2);
if(result==0){
//操作失败,重试
Product productNew = productMapper.selectById(1);
productNew.setPrice(productNew.getPrice()-30);
productMapper.updateById(productNew);
}
//老板来查数据
Product product3 = productMapper.selectById(1);
System.out.println(product3.getPrice());
}
(3)通用枚举
1.在数据库中添加一个sex字段,int类型
2.写个枚举类型:
@Getter
public enum SexEnum{
MALE(1,"男"),
FEMALE(2,"女");
@EnumValue//将注解所标识的属性的值存储到数据库中
private Integer sex;
private String sexName;
SexEnum(Integer sex,String sexName){
this.sex=sex;
this.sexName=sexName;
}
}
3.在配置文件里扫描通用枚举的注解:
4.测试:
@Test
public void test4(){
User user = new User();
user.setName("aehfw");
user.setAge(33);
user.setSex(SexEnum.MALE);
userMapper.insert(user);
}
五.代码生成器
(1)简简单单生成个代码
1.引入依赖
<!--代码生成器依赖--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency>
2.java代码:
public class FastAutoGeneratorTest {
public static void main(String[] args) {
//连接数据库的信息
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "root")
.globalConfig(builder -> { //进行全局配置
builder.author("atguigu") // 设置作者
//.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件,重新生成代码
.outputDir("D://mybatis_plus"); // 指定输出目录
})
.packageConfig(builder -> { //设置当前的包
builder.parent("com.atguigu") // 设置父包名
.moduleName("mybatisplus") // 设置父包模块名,也就是说当前生成的所有内容都在com.atguigu.mybatisplus包下。
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> { //策略配置
builder.addInclude("t_user") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
(2)MyBatisX插件
插件的用法:https://baomidou.com/pages/ba5b24/
快速生成体系结构
1.创建springboot项目
2.引依赖
3.写配置文件
4.先测试能不能连接到数据库
<dependencies>
<!--mybatis-plus场景启动器依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--lombok依赖用于简化实体类开发,注意这个lombok是需要下载插件的-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--数据库驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--默认添加的依赖:spring-boot场景启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--默认添加的依赖:spring-boot测试功能的场景启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
spring:
# 配置数据源信息
datasource:
# 配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
# 配置连接数据库信息
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
username: root
password: root
5.开始使用:
快速生成CRUD:
六.多数据源
适用于多种场景:纯粹多库,读写分离,一主多从,混合模式
我们以以下的场景作为例子:创建两个库,分别是mybatis_plus与mybatis_plus1(新建),将mybatis_plus库中的product表移动到mybatis_plus1表中。这样的话每个库一张表,通过一个测试用例分别获取用户数据与商品数据,如果获取到就说明多库模拟成功。
1.创建数据库和表,添加数据
CREATE DATABASE `mybatis_plus_1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
USE `mybatis_plus_1`;
CREATE TABLE product (
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
price INT(11) DEFAULT 0 COMMENT '价格',
VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id)
);INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);
2. 在上面依赖的基础上添加新的依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.5.0</version> </dependency>
3.配置多数据源:
spring:
# 配置数据源信息
datasource:
dynamic:
# 设置默认的数据源或者数据源组,默认值即为master
primary: master
# 严格匹配数据源:
# false(默认):如果当前匹配不到数据源的时候它会使用当前的默认数据源
# true:未匹配到指定数据源时抛异常
strict: false
datasource:
#主数据源的信息,名字和primary的值保持一致。
master:
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
#从数据源的信息
slave_1:
url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
4.写实体类:
@Data
@TableName("t_user")
public class User {
@TableId
private Integer uid;
private String userName;
private Integer age;
private Integer sex;
private String email;
private Integer isDeleted;
}
@Data
public class Product {
private Integer id;
private String name;
private Integer price;
private Integer version;
}
5.写Service
public interface UserService extends IService<User> {
}
@Service
@DS("master")//使用某个数据源
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
public interface ProductService extends IService<Product> {
}
@Service
@DS("slave_1")
public class ProductServiceImpl extends ServiceImpl<ProductMapper,Product> implements ProductService{
}
6.写mapper
@Component//记得在启动类上进行mapper的包扫描
public interface UserMapper extends BaseMapper<User> {
}
@Component
public interface ProductMapper extends BaseMapper<User> {
}
7.测试
@SpringBootTest
class MybatisPlusDatasourceApplicationTests {
@Autowired
private UserService userService;
@Autowired
private ProductService productService;
@Test
public void test(){
System.out.println(userService.getById(1));
System.out.println(productService.getById(1));
}
}
七.结论:
(1)最后的项目结构:
(2)所有的坐标:
<dependencies>
<!--mybatis-plus场景启动器依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--lombok依赖用于简化实体类开发,注意这个lombok是需要下载插件的-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--数据库驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--默认添加的依赖:spring-boot场景启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--默认添加的依赖:spring-boot测试功能的场景启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--代码生成器依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
</dependencies>