## mybatis plus基本操作
查询方式 说明
setSqlSelect 设置 SELECT 查询字段
where WHERE 语句,拼接 + WHERE 条件
and AND 语句,拼接 + AND 字段=值
andNew AND 语句,拼接 + AND (字段=值)
or OR 语句,拼接 + OR 字段=值
orNew OR 语句,拼接 + OR (字段=值)
eq 等于=
allEq 基于 map 内容等于=
ne 不等于<>
gt 大于>
ge 大于等于>=
lt 小于<
le 小于等于<=
like 模糊查询 LIKE
notLike 模糊查询 NOT LIKE
in IN 查询
notIn NOT IN 查询
isNull NULL 值查询
isNotNull IS NOT NULL
groupBy 分组 GROUP BY
having HAVING 关键词
orderBy 排序 ORDER BY
orderAsc ASC 排序 ORDER BY
orderDesc DESC 排序 ORDER BY
exists EXISTS 条件语句
notExists NOT EXISTS 条件语句
between BETWEEN 条件语句
notBetween NOT BETWEEN 条件语句
addFilter 自由拼接 SQL
last 拼接在最后,例如:last("LIMIT 1")
注意! xxNew 都是另起 ( ... ) 括号包裹。
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
个别参数说明: params : key 为数据库字段名, value 为字段值 null2IsNull : 为 true 则在 map 的 value 为
null 时调用 isNull 方法,为 false 时则忽略 value 为 null 的
- 例1: allEq({id:1,name:“老王”,age:null}) —> id = 1 and name = ‘老王’ and age is null
- 例2: allEq({id:1,name:“老王”,age:null}, false) —> id = 1 and name = '老王’
allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean
null2IsNull)
个别参数说明: filter : 过滤函数,是否允许字段传入比对条件中 ,params 与 null2IsNull : 同上
- 例1: allEq((k,v) -> k.indexOf(“a”) > 0, {id:1,name:“老王”,age:null}) —> name = ‘老王’
and age is null- 例2: allEq((k,v) -> k.indexOf(“a”) > 0, {id:1,name:“老王”,age:null}, false) —> name =
'老王’
代码示例:
@Test
public void testAllEq(){
Map<String,Object> params = new HashMap<>();
params.put("name", "李四");
params.put("age", "20");
params.put("password", null);
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,name,age,email FROM tb_user WHERE (password IS NULL AND name = ? AND age = ?)
// wrapper.allEq(params);
//SELECT id,user_name,name,age,email FROM tb_user WHERE (name = ? AND age = ?)
// wrapper.allEq(params,false);
//过滤函数表示是否允许字段传入比对条件中 params
//SELECT id,user_name,name,age,email FROM tb_user WHERE (password IS NULL AND age = ?)
wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id") || k.equals("password")) , params);
List<User> users = userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testEq() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,name,age,email FROM tb_user WHERE (password = ? AND age >= ? AND name IN (?,?,?))
wrapper.eq("password", "123456")
.ge("age", 20)
.in("name", "李四", "王五", "赵六");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
代码示例:
@Test
public void testLike(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,name,age,email FROM tb_user WHERE (name LIKE ?)
// 参数:%五(String)
wrapper.likeLeft("name", "五");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testOrderByAgeDesc(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//按照年龄倒序排序
// SELECT id,user_name,name,age,email FROM tb_user ORDER BY age DESC
wrapper.orderByDesc("age");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
代码示例:
@Test
public void testOr(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// SELECT id,user_name,name,age,email FROM tb_user WHERE (name = ? OR age = ?)
wrapper.eq("name", "王五").or().eq("age", 21);
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段。
代码示例:
@Test
public void testSelect(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,name,age FROM tb_user WHERE (name = ? OR age = ?)
wrapper.eq("name", "王五")
.or()
.eq("age", 21)
.select("id","name","age"); //指定查询的字段
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
在Mybatis-Plus中提供了ActiveRecord
的模式,支持 ActiveRecord 形式调用,实体类只需继承 Model
类即可实现基本 CRUD 操作,简单来说就是一个实体类继承Model类,并通过注解与数据库的表名进行关联,这样就可以通过实体类直接进行表的简单增删改查操作
实现步骤:
Mapper对象要先继承BaseMapper对象
public interface UserMapper extends BaseMapper<User> {
}
实体对象要继承Model对象
@Data
@TableName("tb_user")
public class User extends Model<User> {
@TableId(value = "id",type = IdType.AUTO)
private Long id;
private String userName;
@TableField(select = false)//查询的时候不查询该字段
private String password;
private String name;
private Integer age;
private String email;
@TableField(exist = false)
private String address; //在数据库表中是不存在的
}
代码测试
@Test
public void testSelectById(){
User user = new User();
user.setId(16L);
//SELECT id,user_name,name,age,email FROM tb_user WHERE id=?
User user1 = user.selectById();
System.out.println(user1);
}
@Test
public void testInsert(){
User user = new User();
user.setUserName("diaochan");
user.setPassword("123456");
user.setAge(20);
user.setName("貂蝉");
user.setEmail("[email protected]");
//INSERT INTO tb_user ( user_name, password, name, age, email ) VALUES ( ?, ?, ?, ?, ? )
// 调用AR的insert方法进行插入数据
boolean insert = user.insert();
System.out.println("result => " + insert);
}
参考博客:https://blog.csdn.net/oneby1314/article/details/116289510
1、 防止全表更新与删除插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 防止全表更新与删除
// 针对 update 和 delete 语句
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
如果进行全表的更新和删除操作则会抛出:MybatisPlusException: Prohibition of table update operation
2、分页插件
插件配置:(SpringBoot)
@Configuration
public class MybatisPlusConfig {
// 配置分页插件,最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
测试:
// 测试分页查询,前提:配置分页插件
@Test
public void testSelectPage(){
Page<User> page = new Page<>(3,2); //查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置查询条件
// wrapper.like("email", "itcast");//like表示模糊查询
IPage<User> iPage = userMapper.selectPage(page, wrapper);
System.out.println("数据总条数: " + iPage.getTotal());
System.out.println("数据总页数: " + iPage.getPages());
System.out.println("当前页数: " + iPage.getCurrent());
List<User> records = iPage.getRecords();
for (User record : records) {
System.out.println(record);
}
}
3、乐观锁插件
插件配置:(SpringBoot)
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
为表添加version字段,并且设置初始值为1
ALTER TABLE `tb_user`
ADD COLUMN `version` int(10) NULL AFTER `email`;
UPDATE `tb_user` SET `version`='1';
为User实体对象添加version字段,并且添加@Version注解
@Version
private Integer version;
测试
@Test
public void testUpdateVersion(){
User user = new User();
user.setId(2L);// 查询条件
User userVersion = user.selectById();
user.setAge(23); // 更新的数据
user.setVersion(userVersion.getVersion()); // 当前的版本信息
boolean result = user.updateById();
System.out.println("result => " + result);
}
注意:
支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
整数类型下 newVersion = oldVersion + 1
newVersion 会回写到 entity 中
SQL注入器主要用于扩充BaseMapper中的方法。以扩展findAll方法为例。
编写MyBaseMapper
public interface MyBaseMapper<T> extends BaseMapper<T> {
List<T> findAll();
}
其他的Mapper都可以继承该Mapper,这样实现了统一的扩展
public interface UserMapper extends MyBaseMapper<User> {
}
编写MySqlInjector
如果直接继承AbstractSqlInjector
的话,原有的BaseMapper中的方法将失效,所以我们选择继承DefaultSqlInjector
进行扩展。
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
// 再扩充自定义的方法
methodList.add(new FindAll());
return methodList;
}
}
编写FindAll
public class FindAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?>
modelClass, TableInfo tableInfo) {
String sqlMethod = "findAll";
String sql = "select * from " + tableInfo.getTableName();
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql,
modelClass);
return this.addSelectMappedStatementForTable(mapperClass, sqlMethod, sqlSource, tableInfo);
}
}
注册到Spring容器
/**
* 自定义SQL注入器
*/
@Bean
public MySqlInjector mySqlInjector(){
return new MySqlInjector();
}
测试
@Test
public void testFindAll(){
List<User> users = this.userMapper.findAll();
for (User user : users) {
System.out.println(user);
}
}
有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、时间等。在MP中提供了这样的功能,可以实现自动填充。
添加@TableField注解
@TableField(fill = FieldFill.INSERT) //插入数据时进行填充
private String password;
自定义实现类 MyMetaObjectHandler
注意:使用@Component
注解标记
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入数据时填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
// 先获取到password的值,再进行判断,如果为空,就进行填充,如果不为空,就不做处理
Object password = getFieldValByName("password", metaObject);
if(null == password){
// setFieldValByName("password", "888888", metaObject);
//或者
this.strictInsertFill(metaObject, "password",String.class,"888889" ); // 起始版本 3.3.0(推荐使用)
}
}
/**
* 更新数据时填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
}
}
测试
@Test
public void testInsert() {
User user = new User();
user.setAge(29);
user.setUserName("guanyu");
user.setName("关于");
//没有设置密码
// user.setPassword("123456");
int result = userMapper.insert(user); //result数据库受影响的行数
System.out.println("result => " + result);
}
逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。
MP就提供了这样的功能,下面看一下怎么使用
修改表结构
为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除。
ALTER TABLE `tb_user`
ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除' AFTER `version`;
同时,也修改User实体,增加deleted属性并且添加@TableLogic注解:
@TableLogic // 逻辑删除字段 ,1-删除,0-未删除
private Integer deleted;
配置
application.properties:
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
测试
删除测试:
@Test
public void testDeleteById(){
// 根据id删除数据
int result = userMapper.deleteById(2L);
System.out.println("result => " + result);
}
@Test
public void testSelectById() {
User user = userMapper.selectById(3L);
System.out.println(user);
}
解决了繁琐的配置,让 mybatis 优雅的使用枚举属性
修改表结构和User实体
ALTER TABLE `tb_user`
ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER `deleted`;
User类中添加sex字段
private SexEnum sex;//性别
定义枚举
public enum SexEnum implements IEnum<Integer> {
MAN(1,"男"),
WOMAN(2,"女");
private int value;
private String desc;
SexEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
@Override
public Integer getValue() {
return this.value;
}
@Override
public String toString() {
return this.desc;
}
}
配置
# 枚举包扫描
mybatis-plus.type-enums-package=com.zb.enums
测试
新增测试:
@Test
public void testInsert(){
User user = new User();
user.setUserName("zhangfei");
user.setPassword("123456");
user.setAge(20);
user.setName("张飞");
user.setEmail("[email protected]");
user.setVersion(1);
user.setSex(SexEnum.WOMAN); //使用的是枚举
// 调用AR的insert方法进行插入数据
boolean insert = user.insert();
System.out.println("result => " + insert);
}
查询测试:
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper、XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
导入依赖
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.3version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-freemarkerartifactId>
dependency>
执行下面代码
//mysql 代码生成器演示例子
public class MysqlGenerator {
/**
*
* 读取控制台内容
*
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
/**
* RUN THIS
*/
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("zhaobin"); //设置作者
gc.setOpen(false);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.zb");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List<FileOutConfig> focList = new ArrayList<>();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return projectPath + "/itcast-mp-generator/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");
strategy.setEntityLombokModel(true);
// strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
strategy.setInclude(scanner("表名"));
strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
// 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
执行结果
MP会生成mapper、service、controller三层,其中service层接口还继承了IService
,service层实现类继承了ServiceImpl
。下面看一下这两个怎么使用。
mp框架同样提供了service层的封装支持,让我们能够简化service层的开发;
service接口继承IService
public interface UserService extends IService<User> {
}
service实现类继承ServiceImpl
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
测试
@Test //测试分页
void testPage() {
//分页查询数据
Page<User> page = userService.page(new Page<User>(1, 2));
System.out.println("数据总条数: " + page.getTotal());
System.out.println("数据总页数: " + page.getPages());
System.out.println("当前页数: " + page.getCurrent());
List<User> records = page.getRecords();
for (User record : records) {
System.out.println(record);
}
}
@Test //测试删除
void testRemove() {
boolean result = userService.removeById(1);
}
好的博客:https://blog.csdn.net/oneby1314/category_11026446.html