MyBatis-Plus(简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。文档地址:https://mybatis.plus/guide/
一、spring-boot整合mybatis-plus (配置文档地址:https://mybatis.plus/guide/config.html,包含spring中的配置)
创建springboot项目,引入mybatis-plus的starter
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
springboot配置文件配置数据源
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: root
sql建表语句
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`u_email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1364106346254659587 DEFAULT CHARSET=utf8;
INSERT INTO `user` (`id`, `name`, `age`, `u_email`) VALUES ('1', 'name2', '13', '[email protected]');
INSERT INTO `user` (`id`, `name`, `age`, `u_email`) VALUES ('2', 'Jack', '28', '[email protected]');
INSERT INTO `user` (`id`, `name`, `age`, `u_email`) VALUES ('3', 'Tom', '18', '[email protected]');
INSERT INTO `user` (`id`, `name`, `age`, `u_email`) VALUES ('4', 'Sandy', '31', '[email protected]');
INSERT INTO `user` (`id`, `name`, `age`, `u_email`) VALUES ('5', 'Billie', '24', '[email protected]');
INSERT INTO `user` (`id`, `name`, `age`, `u_email`) VALUES ('6', 'plus', '19', '[email protected]');
创建Mapper继承BaseMapper
/**
* BaseMapper里mybatis-plus封装了增删改方法
*/
public interface UserMapper extends BaseMapper<User> {
}
创建配置类,添加扫包注解,扫描mapper包
@Configuration
@MapperScan("com.example.demo.mapper")
public class MyBatisPlusConfig {
}
编写测试类,测试查询:
@RunWith(SpringRunner.class)
@SpringBootTest
class DemoApplicationTests {
@Resource
private UserMapper userMapper;
@Test
public void list() {
List<User> list = userMapper.selectList(null);
list.forEach(user -> System.out.println(user.toString()));
}
}
二、条件构造器AbstractWrapper
AbstractWrapper(抽象类)是QueryWrapper(查询)和UpdateWrapper(修改)的父类。QueryWrapper和UpdateWrapper条件拼接的方法一致。
QueryWrapper
@Test
public void query(){
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
Map<String,String> map = new HashMap<>();
map.put("name","plus");
map.put("age","18");
map.put("u_email","[email protected]");
//allEq全部相等 传入map,key为数据库字段,val为对应的值 sql : name = 'plus' and age = '18' and u_email = '[email protected]'
//queryWrapper.allEq(map);
//eq单独字段相等,可以用eq一直拼接字段条件 sql : name = 'Tom' and age = 18
//queryWrapper.eq("name","Tom").eq("age","18");
//ne不等于,无限ne sql : name != 'Tom'
//queryWrapper.ne("name","Tom");
//gt大于 sql : age > 18
//queryWrapper.gt("age",18);
//大于等于 sql : age >= 18
//queryWrapper.ge("age",18);
//lt小于 sql : age < 18
//queryWrapper.lt("age",18);
//le小于等于sql :age <= 18
//queryWrapper.le("age",18);
//between在18到28之间 18 <= age <= 28
//queryWrapper.between("age",18,28);
//notBetween (age < 18 or age > 28)
//queryWrapper.notBetween("age",18,28);
//模糊匹配 sql: name like '%lus%'
//queryWrapper.like("name","lus");
// name not like '%lus%'
//queryWrapper.notLike("name","lus");
//左匹配 sql : name like '%lus'
//queryWrapper.likeLeft("name","lus");
//右匹配 sql name like 'plu%'
//queryWrapper.likeRight("name","plu");
//sql : name is null
//queryWrapper.isNull("name");
//sql : name is not null
//queryWrapper.isNotNull("name");
//in 查询 : id in (1,2,3)
//queryWrapper.in("id", Arrays.asList(1,2,3));
//not in查询 sql: id not in (1,2,3)
//queryWrapper.notIn("id", Arrays.asList(1,2,3));
//条件在查询的数据中,id in (select id from user where id < 3)
//queryWrapper.inSql("id","select id from user where id < 3");
// id not in (select id from user where id < 3)
//queryWrapper.notInSql("id","select id from user where id < 3");
//group by age
//queryWrapper.groupBy("age");
// order by age asc
//queryWrapper.orderByAsc("age");
// order by age desc
//queryWrapper.orderByDesc("age");
//select 指定查询字段,having sum(age) > 18
//queryWrapper.select("name").groupBy("name").having("sum(age) > 18");
//func支持传入方法
/* queryWrapper.func(w -> {
if(false){
w.eq("name","plus");
}else {
w.eq("name","Tom");
}
});*/
// 相当于 name = 'plus' or (name = 'Tom' and age = '18')(默认都为and)
//queryWrapper.eq("name","plus").or().eq("name","Tom").eq("age","18");
//相当于 age = 18 or (name = 'plus' or name = 'Tom')
/* queryWrapper.eq("age",18).or(i -> {
i.eq("name","plus").or().eq("name","Tom");
});*/
//相当于 id = 3 and (name = 'Tom' and age = '18') , and方法相当于里面小括号外加and
/*queryWrapper.eq("id",3).and(i->{
i.eq("name","Tom").eq("age",18);
});*/
/* //正常嵌套 (name = 'plus' and age = '19')
queryWrapper.nested(i->{
i.eq("name","plus").eq("age",19);
});*/
//用于数据库函数 sql : where LEFT(name,2) = 'To'
//queryWrapper.apply("LEFT(name,2) = 'To'");
//直接拼接sql后面
queryWrapper.last("limit 1");
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
UpdateWrapper
@Test
public void update(){
//修改,不仅会修改实体的内容,也会修改set方法里的内容,字段值设为null,set("u_email",null)
User user = new User();
user.setName("name");
user.setAge(13);
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("u_email","[email protected]");
updateWrapper.setSql("name = 'name2'");
updateWrapper.eq("id",1);
//userMapper.update(user,updateWrapper);
userMapper.update(null,updateWrapper);
}
三、自定义sql
注解方式,直接定义方法,注解方式查询:
public interface UserMapper extends BaseMapper<User> {
@Select("select * from user where id = #{id}")
User findById(@Param("id")String id);
/**
* 映射xml文件方法
* @param name
* @return
*/
User findUserByName(String name);
}
xml文件方式:
定义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 id="BaseResultMap" type="com.example.demo.core.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="uEmail" column="u_email"/>
</resultMap>
<select id="findUserByName" parameterType="java.lang.String" resultMap="BaseResultMap">
select * from user where `name` = #{name}
</select>
</mapper>
mybatis-plus配置:
# 如果xml文件在classpath下mapper文件夹下不配置也可以,如果不是就需要配上xml文件路径
mybatis-plus:
mapper-locations: classpath*:mapper/*Mapper.xml
查询测试:
@Test
public void findById(){
//注解方式
User user = userMapper.findById("1");
System.out.println(user.toString());
}
@Test
public void findByName(){
//xml文件方式
User user = userMapper.findUserByName("plus");
System.out.println(user.toString());
}
三、分页
添加分页插件,注册成bean
@Configuration
@MapperScan("com.example.demo.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
mapper接口和xml定义分页查询方法(普通的查询,mybatis-plus自动添加分页,按分页规则写查询方法)
//UserMapper的分页方法
IPage<User> findUserPage(Page<User> userPage);
<!--UserMapper.xml中的分页方法-->
<select id="findUserPage" resultMap="BaseResultMap">
select * from `user`
</select>
分页测试代码
@Test
public void findPage(){
int pageNo = 2; //页码
int pageSize = 2; //每页数据条数
Page<User> page = new Page<>(pageNo,pageSize);
IPage<User> iPage = userMapper.findUserPage(page);
System.out.println("数据总条数:" + iPage.getTotal());
System.out.println("总页数:" + iPage.getPages());
iPage.getRecords().forEach(System.out::println);
}
自定义分页类,带入对象信息查询:
/**
* 创建Pager类,继承Page类,自定义condition字段接收查询条件对象
*/
public class Pager<T> extends Page<T> {
/**
* 条件参数
*/
private T condition;
public T getCondition() {
return condition;
}
public void setCondition(T condition) {
this.condition = condition;
}
public Pager(int pageNo, int pageSize){
super(pageNo,pageSize);
}
}
UserMapper和UserMapper.xml
/**
* 自定义Pager,传入查询条件(实体)
* @param pager
* @return
*/
IPage<User> findPageByCondition(Pager<User> pager);
<select id="findPageByCondition" resultMap="BaseResultMap" parameterType="com.example.demo.page.Pager">
select * from `user`
<where>
<if test="condition != null">
<if test="condition.name != null and condition.name != ''">
and `name` = #{condition.name}
</if>
<if test="condition.age != null">
and age = #{condition.age}
</if>
</if>
</where>
</select>
查询测试:
@Test
public void findPageByCondition(){
//查询条件对象
User user = new User();
//user.setName("plus");
user.setAge(19);
int pageNo = 1; //页码
int pageSize = 2; //每页数据条数
Pager<User> pager = new Pager<>(pageNo,pageSize);
pager.setCondition(user);
IPage<User> iPage = userMapper.findPageByCondition(pager);
System.out.println("数据总条数:" + iPage.getTotal());
System.out.println("总页数:" + iPage.getPages());
iPage.getRecords().forEach(System.out::println);
}
四、多数据源
1、引入dynamic-datasource-spring-boot-starter
dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
2、配置文件
spring:
datasource:
dynamic:
primary: master #默认数据源或数据组,默认为master
strict: false #设置严格模式,默认false。启动未匹配到默认数据源会报错不会使用默认数据源
datasource:
master:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: root
driverClassName: com.mysql.cj.jdbc.Driver
master_1:
url: jdbc:mysql://190.168.65.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: root
driverClassName: com.mysql.cj.jdbc.Driver
3、使用 @DS注解切换数据源。方法上的注解优先于类上的注解
//可用在类、接口和方法上
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {
String value();
}
@Service
@DS("master_1")
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@DS("master") //就近原则,方法上的注解优先于类上的注解
@Override
public void insertUser(User user) {
userMapper.insert(user);
}
}
4、添加测试,修改数据源
@Test
public void insert(){
User user = new User();
user.setName("数据源");
user.setAge(20);
user.setUEmail("[email protected]");
userService.insertUser(user);
}