学习MyBatis-Plus
<!--整合mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
常用注解@TableName、@TableId、@TableField
@TableName
实体类的名字与数据库表名不一样时,可以用这个注解指定表名
@TableName("mp_user") //指定表名为mp_user
public class User {
private Long id;
private String name;
private Integer age;
private String email;
//下面都是get、set和toString方法,就省略不放上来了
}
@TableId
实体类的主键的属性名和表里主键的字段名不一致的时候可以用这个注解指定
public class User {
@TableId
private Long id;
private String name;
private Integer age;
private String email;
//下面都是get、set和toString方法,就省略不放上来了
}
@TableField
实体类的属性名与表里的字段名不一致时用这个注解指定
public class User {
private Long id;
@TableField("username")
private String name;
private Integer age;
private String email;
//下面都是get、set和toString方法,就省略不放上来了
}
排除实体类属性里非表字段的方式
有一种场景,在一个实体类里,并不是所有属性都一一对应着表里的数据,有几个属性在表里是没有对应字段的,这时可以用@TableField(exist = false)
public class User {
private Long id;
private String name;
private Integer age;
private String email;
@TableField(exist = false) //这里默认是true的
private String note;
//下面都是get、set和toString方法,就省略不放上来了
}
查询方法
创建mapper接口,BaseMapper的泛型就是你要操作的实体类
public interface UserMapper extends BaseMapper<User> {}
selectById()
根据id查询,参数值只要实现Serializable序列化接口的类型都可以,如String、Integer
User user = userMapper.selectById(2L); //这里传入Long类型的
selectBatchIds()
根据id批量查询,传入参数要集合类型的
List<Long> idList = new ArrayList<>();
idList.add(2L);
idList.add(4L);
idList.add(5L);
List<User> users = userMapper.selectBatchIds(idList);
这里users集合就是根据那几个id查询的结果
selectByMap()
根据传入的字段和字段的值来查询,传入参数要Map<String,Object> 类型的,键就是数据库表里的字段(不是java实体类的属性名!),值就是字段对应的值。
Map<String,Object> columnMap = new HashMap<>();
columnMap.put("name","Jack");
columnMap.put("age",20);
/*
这里就相当于SQL语句select .... from ... where name = "Jack" and age = 20
所以columnMap里的键必须是表里的字段名,而不是实体类的属性名
*/
List<User> users = userMapper.selectByMap(columnMap);
条件构造器查询QueryWrapper
用条件构造器把你想要的条件设置好,再传入查询的方法。
like,lt
/*
假设要查询name里包含ac的并且age小于30的数据
SQL语句:.... where name like '%ac%' and age<30
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.like("name","ac").lt("age",30);
List<User> users = userMapper.selectList(queryWrapper);
注意,这里的like(),lt()(和其他类似的方法,这里没列出),他们的第1个参数是指数据库里表的字段名,不是实体类的属性名!
/*
假设要查询name里以S开头的或者10<age<30,并且email不为空,根据age降序排列的数据
SQL语句:.... where name like 'S%' or age between 10 and 30 and email is not null
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.likeRight("name","S").or().between("age",10,30)
.isNotNull("email").orderByDesc("age");
List<User> users = userMapper.selectList(queryWrapper);
这里likeRight()表示%在右边,or()表示SQL里的or。
apply,inSql
/*
要查询的SQL语句age小于30 同时 id在这个范围里(模糊查询 name中带有a字符的)
SELECT * FROM `user` WHERE age<30 AND id IN (SELECT id FROM `user` WHERE `name` LIKE '%a%')
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.apply(" age<30").inSql("id","SELECT id FROM `user` WHERE `name` LIKE '%a%'");
List<User> users = userMapper.selectList(queryWrapper);
apply()用来拼接SQL语句,注意SQL注入的风险!
inSql()用来做子查询,参数1为子查询的列,参数2为子查询的语句
and
有()优先顺序的查询语句
/*要查询的语句名字里有a并且(年龄小于30或邮箱不为空)
SELECT * FROM `user` WHERE `name` LIKE '%a%' AND (age<30 OR email IS NOT NULL)
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.like("name","a").and(qw->qw.lt("age",30).or().isNotNull("email"));
List<User> users = userMapper.selectList(queryWrapper);
and()表示AND 嵌套,nested()表示正常嵌套 不带 AND 或者 OR
/*要查询的语句(年龄小于30或邮箱不为空)并且名字里有a
SELECT * FROM `user` WHERE (age<30 OR email IS NOT NULL) AND `name` LIKE '%a%'
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.nested(qw->qw.lt("age",30).or().isNotNull("email")).like("name","a");
List<User> users = userMapper.selectList(queryWrapper);
in
in(),里面的参数可以是数组
/*
SELECT * FROM `user` WHERE age IN (20,28,22)
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.in("age", Arrays.asList(20,22,28));
List<User> users = userMapper.selectList(queryWrapper);
last
返回满足条件的1条数据可以用last(),无视优化规则直接拼接到 sql 的最后,有SQL注入风险
/*
SELECT * FROM `user` WHERE age IN (20,28,22) LIMIT 1
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.in("age", Arrays.asList(20,22,28)).last("limit 1");
List<User> users = userMapper.selectList(queryWrapper);
select
上面的查询语句都会把全部字段都查出来,如果只想查询几个字段,可以用select(),参数就是列名,可以有多个参数
/*
假设要查询name里包含ac的并且age小于30的数据
SQL语句:select id,name from `user` where name like '%ac%' and age<30
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.select("id","name").like("name","ac").lt("age",30);
List<User> users = userMapper.selectList(queryWrapper);
1张表可能有十几个字段,如果单独想查2、3个字段的话,用上面的方法挺方便的,但是如果有15个字段,我只想查13个字段,把13个字段都写上去又挺麻烦,那我们就可以只排除2个字段,剩下的就是我们要查的数据了。
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.select(User.class,info->!info.getColumn().equals("age")&&
!info.getColumn().equals("email")).like("name","ac").lt("age",30);
List<User> users = userMapper.selectList(queryWrapper);
condition参数
在使用一些QueryWrapper的方法时,有些方法可以有3个参数,如like()方法,查看源码:
default Children like(R column, Object val) {
return this.like(true, column, val);
}
like()有3个参数,但是当你对like()方法传入2个参数时,他把第1个参数设置为true,后面2个参数就是你传进来的参数。
like()有3个参数,它的第1个是boolean类型的:
- 当它为true时,就把后面2个参数放到SQL语句的where后面进行使用
- 当它为false时,就不把后面2个参数放到SQL语句的where后面进行使用,等于你没有设置这个条件
使用场景:有一个页面展示员工数据列表,列表上面可以进行多条件搜索而且不一定都得填上,比如有2个输入框分别可以输入name,email进行搜索,但是我不一定2个输入框都有输入数据,比如我只输入了name然后点击搜索,后端不知道会发来几个数据就会先对2个参数进行判空,如下:
void tempFunc(String name,String email){
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
if (name != null && !"".equals(name)){
queryWrapper.like("name",name);
}
if (email != null && !"".equals(email)){
queryWrapper.like("email",email);
}
//......
}
利用方法里的condition参数,可以改为这样:
void mpTest() {
String name = "a";
String email = "";
tempFunc(name,email);
}
void tempFunc(String name,String email){
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
/*if (name != null && !"".equals(name)){
queryWrapper.like("name",name);
}
if (email != null && !"".equals(email)){
queryWrapper.like("email",email);
}*/
queryWrapper.like(name != null && !"".equals(name),"name",name)
.like(email != null && !"".equals(email),"email",email);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}
实体类对象作为条件构造器的构造方法的参数
User user = new User();
user.setName("Jack");
user.setAge(20);
QueryWrapper<User> queryWrapper = new QueryWrapper<User>(user);
List<User> users = userMapper.selectList(queryWrapper);
生成的SQL是这样的:
'DEBUG==> Preparing: SELECT id,name,age,email FROM user WHERE name=? AND age=?
''DEBUG==> Parameters: Jack(String), 20(Integer)
会把实体类对象的属性作为等值条件,你设置了name,他就给你加where name= 的条件。
如果queryWrapper再添加一些条件也是没问题的,像这样:
User user = new User();
user.setName("Jack");
user.setAge(20);
QueryWrapper<User> queryWrapper = new QueryWrapper<User>(user);
queryWrapper.like("email","abc");
实体类对象作为参数传入条件构造器的构造方法里,默认是作为等值条件的,如果不想做等值的判断(…where name= 就像这样),我想实现name like '%a%'这样的条件,可以这么做修改实体类:
public class User {
private Long id;
private String name;
private Integer age;
@TableField(condition = SqlCondition.LIKE) //加这句
private String email;
//省略get set toString方法
}
这样再传入实体类对象时
User user = new User();
user.setEmail("123abc@qq.com");
QueryWrapper<User> queryWrapper = new QueryWrapper<User>(user);
他就把对应属性使用like模糊查询条件,生成的SQL是这样的:
'DEBUG==> Preparing: SELECT id,name,age,email FROM user WHERE email LIKE CONCAT('%',?,'%')
''DEBUG==> Parameters: tes(String)
不只是有like,还有很多条件,具体看@TableField(condition)的condition都有哪些值,甚至自定义都行。
allEq
allEq()可以传入一个Map类型的集合,键写表的字段名,值就写字段对应的值
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
Map<String , Object> map = new HashMap<>();
map.put("name","Jack");
map.put("age",null);
queryWrapper.allEq(map);
List<User> users = userMapper.selectList(queryWrapper);
生成的SQL如下,map里的数据作为等值判断:
'DEBUG==> Preparing: SELECT id,name,age,email FROM user WHERE (name = ? AND age IS NULL)
''DEBUG==> Parameters: Jack(String)
当字段的值为null时(就像上面的age那样),生成的SQL就为IS NULL条件
如果allEq(),第2个参数为false时:
queryWrapper.allEq(map,false);
就表示map里面为null的数据就会忽略,不会出现在SQL里
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
Map<String , Object> map = new HashMap<>();
map.put("name","Jack");
map.put("age",null);
queryWrapper.allEq(map,false);
List<User> users = userMapper.selectList(queryWrapper);
生成的SQL为:
'DEBUG==> Preparing: SELECT id,name,age,email FROM user WHERE (name = ?)
''DEBUG==> Parameters: Jack(String)
allEq()还可以这样写:
queryWrapper.allEq((k,v)->!k.equals("name"),map);
这里第1个参数是个过滤函数,返回的是个boolean值,当返回false时,字段的值就不会出现在SQL里。这里表示当map里有name键时,就不把name放到SQL里。
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
Map<String , Object> map = new HashMap<>();
map.put("name","Jack");
map.put("age",null);
queryWrapper.allEq((k,v)->!k.equals("name"),map);
List<User> users = userMapper.selectList(queryWrapper);
生成的SQL:
'DEBUG==> Preparing: SELECT id,name,age,email FROM user WHERE (age IS NULL)
''DEBUG==> Parameters:
可以看到没了name 的条件。
Mapper的selectMaps()方法
上面查询的结果都是封装到List<User>类型的集合里面,现在有个使用场景:一个表有20个字段,我只想查2个,用之前的方法也可以,但是有些字段可能是null没有数据的,这样List<User>类型的集合里,很多实体对象的属性就是null,这样不好看。可以这样:
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.select("id","name").like("name","ac");
List<Map<String,Object>> users = userMapper.selectMaps(queryWrapper);
查询的结果
[{name=Jack, id=2}]
其他age,email的属性无论是否null,都不会显示出来
查询统计数据
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.select("avg(age) avgAge");
List<Map<String,Object>> users = userMapper.selectMaps(queryWrapper);
查询的SQL:
'DEBUG==> Preparing: SELECT avg(age) avgAge FROM user
''DEBUG==> Parameters:
''TRACE<== Columns: avgAge
''TRACE<== Row: 22.1667
''DEBUG<== Total: 1
'[{avgAge=22.1667}]
Mapper的selectObjs()方法
只返回查询的第1列数据
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.select("name,age");
List<Object> users = userMapper.selectObjs(queryWrapper);
虽然这里代码写是查询name,age两列数据,但是最终users里只有第1列数据,也就是name列的数据
Mapper的selectCount()方法
顾名思义,就是用来统计查询结果数的
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
Integer users = userMapper.selectCount(queryWrapper);
查询的SQL语句:
SELECT COUNT( * ) FROM user
Mapper的selectOne()方法
查询1条数据(没有符合要求的数据也行),注意条件的设置,如果查询返回超过1条数据会报错
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.like("name","Jac");
User user = userMapper.selectOne(queryWrapper);
lambda条件构造器
//创建lambda条件构造器的3种方式
//LambdaQueryWrapper<User> lambdaQueryWrapper = new QueryWrapper<User>().lambda();
//LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>();
LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.<User>lambdaQuery();
//查询...where name like "%ac%"
LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.<User>lambdaQuery();
lambdaQueryWrapper.like(User::getName,"ac");
List<User> users = userMapper.selectList(lambdaQueryWrapper);
这里User::getName我也不是很理解,看网上说是能自动找到实体类的属性名即name,这里name正好对应着数据库里表的字段名name,所以可以使用。这样写可以防止写错
List<User> list = new LambdaQueryChainWrapper<User>(userMapper).like(User::getName, "ac").list();
这种写法就可以直接返回查询结果
自定义SQL
注解方式
public interface UserMapper extends BaseMapper<User> {
//注意这里不用写where,mybatisPlus会帮我们加
@Select("select * from user ${ew.customSqlSegment}")
List<User> selectAll(@Param(Constants.WRAPPER)Wrapper<User> wrapper);
}
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.like("name","ac");
List<User> users = userMapper.selectAll(queryWrapper); //这里就用上面自己写的方法
XML方式
目录形式
userMapper.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
<mapper namespace="com.mybatisplus.mpdemo.dao.UserMapper">
<select id="selectAll" resultType="com.mybatisplus.mpdemo.entity.User">
select * from user ${ew.customSqlSegment}<!--注意这里也是不用写where的-->
</select>
</mapper>
UserMapper接口
public interface UserMapper extends BaseMapper<User> {
List<User> selectAll(@Param(Constants.WRAPPER)Wrapper<User> wrapper);
}
application.properties添加配置
mybatis-plus.mapper-locations=classpath:/mapper/*
测试用例与上面注解方式一样照常使用即可。
分页
MyBatisPlusConfig配置类
@Configuration
public class MyBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
方法一
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.like("name","a");
Page<User> page = new Page<>(1, 2);
IPage<User> userPage = userMapper.selectPage(page, queryWrapper);
System.out.println("总页数:"+userPage.getPages());
System.out.println("总记录数:"+userPage.getTotal());
List<User> records = userPage.getRecords();//查询的数据
方法二
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.like("name","a");
IPage<Map<String,Object>> page = new Page<>(1, 2);
IPage<Map<String,Object>> userPage = userMapper.selectMapsPage(page,queryWrapper);
System.out.println("总页数:"+userPage.getPages());
System.out.println("总记录数:"+userPage.getTotal());
List<Map<String,Object>> records = userPage.getRecords();//查询的数据
注意
IPage<Map<String,Object>> page = new Page<>(1, 2,false);
如果构造函数的第3个参数设置为false,表示不需要查总记录数,测试发现
System.out.println("总页数:"+userPage.getPages()); //输出0
System.out.println("总记录数:"+userPage.getTotal()); //输出0
自定义的写法
UserMapper接口
public interface UserMapper extends BaseMapper<User> {
IPage<User> selectUserPage(Page<User> page,@Param(Constants.WRAPPER)Wrapper<User> wrapper);
}
userMapper.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
<mapper namespace="com.mybatisplus.mpdemo.dao.UserMapper">
<select id="selectUserPage" resultType="com.mybatisplus.mpdemo.entity.User">
select * from user ${ew.customSqlSegment}<!--注意这里也是不用写where的-->
</select>
</mapper>
与自定义SQL小节的目录形式、properties配置文件都是一样。
测试
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.like("name","a");
Page<User> page = new Page<>(1, 2);
IPage<User> userPage = userMapper.selectUserPage(page,queryWrapper);
System.out.println("总页数:"+userPage.getPages());
System.out.println("总记录数:"+userPage.getTotal());
List<User> records = userPage.getRecords();//查询的数据
更新方法
方法1
User user = new User();
user.setId(2L);
user.setName("Jack");
user.setAge(21);
user.setEmail("test2@baomidou.com");
int row = userMapper.updateById(user);//row为影响记录数
SQL语句
'DEBUG==> Preparing: UPDATE user SET name=?, age=?, email=? WHERE id=?
''DEBUG==> Parameters: Jack(String), 21(Integer), test2@baomidou.com(String), 2(Long)
方法2
User user = new User();
user.setAge(22);
user.setEmail("test2@baomidou.com");
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.like("name","Jack");
int row = userMapper.update(user,wrapper);
//实体类对象的属性会出现在SQL的set部分,wrapper的条件会出现在SQL的where部分
SQL
'DEBUG==> Preparing: UPDATE user SET age=?, email=? WHERE (name LIKE ?)
''DEBUG==> Parameters: 22(Integer), test2@baomidou.com(String), %Jack%(String)
方法3
User whereUser = new User();
whereUser.setName("Jack");
User user = new User();
user.setAge(30);
UpdateWrapper<User> wrapper = new UpdateWrapper<>(whereUser);
wrapper.eq("email","test2@baomidou.com");
int row = userMapper.update(user,wrapper);
这里的whereUser对象的属性会加入到SQL的where语句部分,whereUser要传入UpdateWrapper的构造函数中
SQL
'DEBUG==> Preparing: UPDATE user SET age=? WHERE name=? AND (email = ?)
''DEBUG==> Parameters: 30(Integer), Jack(String), test2@baomidou.com(String)
方法4
如果不想通过new User()创建实体类对象来传入SQL语句的set部分,可以这样:
User whereUser = new User();
whereUser.setName("Jack");
/*
User user = new User();
user.setAge(30);
*/
UpdateWrapper<User> wrapper = new UpdateWrapper<>(whereUser);
wrapper.eq("email","test2@baomidou.com").set("age",40); //使用set()方法设置SQL中要更新的字段和值
int row = userMapper.update(null,wrapper);
System.out.println("影响记录数:"+row);
SQL
'DEBUG==> Preparing: UPDATE user SET age=? WHERE name=? AND (email = ?)
''DEBUG==> Parameters: 40(Integer), Jack(String), test2@baomidou.com(String)
方法5
用lambda语句
LambdaUpdateWrapper<User> wrapper = Wrappers.<User>lambdaUpdate();
wrapper.eq(User::getEmail,"test2@baomidou.com").set(User::getAge,50);
int row = userMapper.update(null,wrapper);
System.out.println("影响记录数:"+row);
SQL
'DEBUG==> Preparing: UPDATE user SET age=? WHERE (email = ?)
''DEBUG==> Parameters: 50(Integer), test2@baomidou.com(String)
方法6
用链式的lambda
boolean result = new LambdaUpdateChainWrapper<User>(userMapper)
.eq(User::getEmail, "test2@baomidou.com").set(User::getAge, 50).update();
这里的result表示是否更新成功
删除方法
方法1
int i = userMapper.deleteById(5); //根据id删除
返回结果为删除的条数
方法2
Map<String, Object> map = new HashMap<>();
map.put("name","Tom");
map.put("email","test2@baomidou.com");
int i = userMapper.deleteByMap(map);
SQL
'DEBUG==> Preparing: DELETE FROM user WHERE name = ? AND email = ?
''DEBUG==> Parameters: Tom(String), test2@baomidou.com(String)
使用map传入where部分的条件。
方法3
//根据id批量删除,这里传入构造函数的就是存有id的列表
int i = userMapper.deleteBatchIds(Arrays.asList(10,20,30));
SQL
'DEBUG==> Preparing: DELETE FROM user WHERE id IN ( ? , ? , ? )
''DEBUG==> Parameters: 10(Integer), 20(Integer), 30(Integer)
方法4
使用lambda表达式
LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery();
wrapper.eq(User::getEmail,"test3@baomidou.com");
int i = userMapper.delete(wrapper);
'DEBUG==> Preparing: DELETE FROM user WHERE (email = ?)
还有其他方式进行删除,与上面查询的方法类似,如创建User实体类对象,set方法设置user对象的一些属性,再把user对象传入Wrapper作为SQL的where 条件,等等。
AR模式
一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。
实体类
public class User extends Model<User> {
private Long id;
private String name;
private Integer age;
private String email;
//省略get、set、toString方法
}
插入
User user = new User();
user.setId(10L);
user.setAge(25);
user.setName("ka");
user.setEmail("10te@qq.com");
boolean i = user.insert();
System.out.println("结果:"+i);
根据id查询
User user = new User();
User result = user.selectById(2L);
System.out.println(user==result); //false
System.out.println("结果:"+result);
结果
'DEBUG==> Preparing: SELECT id,name,age,email FROM user WHERE id=?
''DEBUG==> Parameters: 2(Long)
''TRACE<== Columns: id, name, age, email
''TRACE<== Row: 2, Jack, 60, test2@baomidou.com
''DEBUG<== Total: 1
'false
结果:User{id=2, name='Jack', age=60, email='test2@baomidou.com'}
另一种写法
User user = new User();
user.setId(2L); //通过user对象设置等值条件
User result = user.selectById();
System.out.println(user==result);
System.out.println("结果:"+result);
结果与上面一样
更新
User user = new User();
user.setId(2L);
user.setName("coco");
boolean result = user.updateById();
System.out.println("结果:"+result);
'DEBUG==> Preparing: UPDATE user SET name=? WHERE id=?
''DEBUG==> Parameters: coco(String), 2(Long)
''DEBUG<== Updates: 1
'结果:true
删除
User user = new User();
user.setId(2L);
boolean result = user.deleteById();
System.out.println("结果:"+result);
'DEBUG==> Preparing: DELETE FROM user WHERE id=?
''DEBUG==> Parameters: 2(Long)
''DEBUG<== Updates: 1
'结果:true
删除或更新
User user = new User();
user.setId(2L);
user.setAge(30);
boolean result = user.insertOrUpdate();
System.out.println("结果:"+result);
insertOrUpdate()如果user有id,那么它就根据id去修改信息;如果user没有id,它就会插入信息
主键策略
如果数据库表里设置了主键自增,是可以在代码中返回插入数据的id值的
User user = new User();
user.setName("cba");
user.setAge(30);
int i = userMapper.insert(user);
System.out.println("主键:"+user.getId());
'DEBUG==> Preparing: INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )
''DEBUG==> Parameters: 1417751961234583554(Long), cba(String), 30(Integer)
''DEBUG<== Updates: 1
'主键:1417751961234583554
public class User extends Model<User> {
//设置主键策略(局部的),UUID 是String类型的,数据库表里的主键也要字符串类型
@TableId(type = IdType.UUID)
private String id;
//...省略其他属性,set、get、toString方法
}
全局配置主键策略
application.properties设置全局配置主键策略
mybatis-plus.global-config.db-config.id-type=uuid
那么实体类的id属性就可以不用配置策略了
public class User extends Model<User> {
private String id;
//...省略其他属性,set、get、toString方法
}
如果实体类的id属性还是配置了局部主键策略,即全局和局部的主键策略同时存在,系统以局部的主键策略优先。
基本配置
如果你有自己的mybatis配置文件,可以这样写告诉系统在哪里:
mybatis-plus.config-location=classpath:mybatis-config.xml
mapper的xml文件存放位置
mybatis-plus.mapper-locations=classpath:/mapper/*
配置包别名
mybatis-plus.type-aliases-package=com.mybatisplus.mpdemo.entity
这样在mapper.xml的<namespace>就可以不用写全限定类名了
<mapper namespace="com.mybatisplus.mpdemo.dao.UserMapper">
<select id="selectUserPage" resultType="com.mybatisplus.mpdemo.entity.User">
select * from user ${ew.customSqlSegment}<!--注意这里也是不用写where的-->
</select>
</mapper>
<!--配置包别名后-->
<mapper namespace="UserMapper">
<!--......-->
</mapper>
注意,configuration和config-location这两个不能同时出现,会报错
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.config-location=classpath:mybatis-config.xml
配置表名前缀,假设公司统一表名前缀为mp_,你又不想改java实体类的类名,就可以这样:
mybatis-plus.global-config.db-config.table-prefix=mp_
这里mybatis-plus在执行SQL时会自动拼上,如你的实体类类名是User,那么它会自动把SQL的表名拼为mp_user
通用Service
service接口
public interface UserService extends IService<User> { //这里的泛型就是你要操作的实体类
}
service实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
//上面的泛型UserMapper就是你用来操作实体的mapper,User就是你要操作的实体类
}
测试
@Autowired
UserService userService;
@Test
void mpTest() {
User one = userService.getOne(Wrappers.<User>lambdaQuery().gt(User::getAge, 18), false);
System.out.println(one);
}
getOne()方法的第二个参数设置为false,表示如果查询到多于1条数据,那么就返回查询到的第1条数据给你;如果设置为true或不填,当查询到多于1条数据时就会报错。
批量插入
User user1 = new User();
user1.setName("QQ");
User user2 = new User();
user2.setName("ER");
List<User> users = Arrays.asList(user1, user2);
boolean result = userService.saveBatch(users);
System.out.println(result);
User user1 = new User();
user1.setName("QQ");
User user2 = new User();
user2.setId(1417772304762458113L);
user2.setName("ER_after");
List<User> users = Arrays.asList(user1, user2);
boolean result = userService.saveOrUpdateBatch(users);
System.out.println(result);
saveOrUpdateBatch()方法就是如果实体类对象里有id,那么就先根据id查询看有没有这条数据,如果有,就根据id执行更新操作,如果没有就插入;如果实体类对象里没有id,就直接执行插入操作。
链式操作
List<User> list = userService.lambdaQuery().gt(User::getAge, 18).list(); //查询
'DEBUG==> Preparing: SELECT id,name,age,email FROM user WHERE (age > ?)
''DEBUG==> Parameters: 18(Integer)
''TRACE<== Columns: id, name, age, email
''TRACE<== Row: 10, ka, 25, 10te@qq.com
''TRACE<== Row: 4, Sandy, 21, test4@baomidou.com
''TRACE<== Row: 123, 小ge, 22, 123@qq.com
''TRACE<== Row: 1417751961234583554, cba, 30, null
''TRACE<== Row: 1417763990062256130, cbadd, 30, null
''DEBUG<== Total: 5
boolean result = userService.lambdaUpdate().eq(User::getName, "Jone").set(User::getAge, 50).update(); //更新
System.out.println(result);
'DEBUG==> Preparing: UPDATE user SET age=? WHERE (name = ?)
''DEBUG==> Parameters: 50(Integer), Jone(String)
''DEBUG<== Updates: 1
'true
boolean result = userService.lambdaUpdate().eq(User::getName, "ER").remove(); //删除
System.out.println(result);
'DEBUG==> Preparing: DELETE FROM user WHERE (name = ?)
''DEBUG==> Parameters: ER(String)
''DEBUG<== Updates: 0
'false