导入依赖
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.1version>
dependency>
导入数据库
DROP TABLE IF EXISTS USER;
CREATE TABLE USER
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
DELETE FROM USER;
INSERT INTO USER (id, NAME, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
spring.datasource.username=root
spring.datasource.password=123123
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncodind=utf8&useSSL=true&serverTimezone=GMT
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
//在对应的mapper上面继承基本的类 BaseMapper
@Repository//代表持久层
public interface UserMapper extends BaseMapper<User> {
//所有CRUD操作都已经编写完成了
//你不需要向以前一样配置一大堆文件了!
}
@MapperScan("com.lyk.mapper")
@SpringBootTest
class MybatisPlusHelloApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
测试成功,我们发现真的不用写那些基础的CURD操作了!!!
配置日志 (默认控制台输出)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
这样我们就可以在控制台上看到执行细节了
默认生成,通过雪花算法生成ID 参考博客:https://blog.csdn.net/lq18050010830/article/details/89845790
==> Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
==> Parameters: 1423577873627734017(Long), 李永康(String), 19(Integer), [email protected](String)
可以观察到@TableId注解下有很多主键生成方案
AUTO(0),自增长ID,前提是将数据库设置为自增长
INPUT(2),自己输入ID
ASSIGN_ID(3),雪花算法,默认
ASSIGN_UUID(4),不带下划线的UUID,但是是String类型的
通过updateById方法(参数传入一个对象,而不是一个值)
通过实践发现,Mybatis-Plus是帮我们自动拼接了动态sql
@Test
void updateText(){
User user = new User();
user.setId(8848L);
user.setAge(15);
// user.setName("李晶晶");
userMapper.updateById(user);
}
当我们为对象只注入Age属性的时候
sql是这样的:==> Preparing: UPDATE user SET age=? WHERE id=?
@Test
void updateText(){
User user = new User();
user.setId(8848L);
user.setAge(15);
user.setName("李晶晶");
userMapper.updateById(user);
}
当我们即注入的Age,还注入了Name的时候
sql是这样的:Preparing: UPDATE user SET name=?, age=? WHERE id=?
由此可见,Mybatis-Plus帮我们封装的动态sql
gmt_create (创建时间)gmt_modified(修改时间)这两个属性都需要操作自动化完成,我们并不能手动的去控制。
先在数据库里加上这两个字段
然后更改实体类,在要操作的字段上加@TableField注解,注意这里是时间的类型是LocalDateTime
@TableField(fill = FieldFill.INSERT)
private LocalDateTime gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime gmtModified;
这个注解下有一个FieldFill类下有这么几个常量
DEFAULT,
INSERT,
UPDATE,
INSERT_UPDATE;
然后写一个类实现MetaObjectHandler接口
这个类必须@Component注册为组件
public void insertFill(MetaObject metaObject)是执行插入时候执行的方法
public void updateFill(MetaObject metaObject)是修改时执行的方法
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("gmtCreate", LocalDateTime.now(), metaObject);
this.setFieldValByName("gmtModified",LocalDateTime.now(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified",LocalDateTime.now(),metaObject);
}
}
测试即可
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version(作为oldVersion)
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
在数据库新增一个version列,默认值为1
在实体类中同样增加version,并且加上@version注解
@Configuration
@MapperScan("com.lyk.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
测试即可,在使用乐观锁更细之前,需要先查询,获取到被更新的对象。
//测试查询
@Test
public void testSelectById(){
User user = userMapper.selectById(1l);
System.out.println(user);
}
//测试批量查询
@Test
public void testSelectByBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}// 按条件查询之一使用map操作
@Test
public void testSelectByBatchIds(){
HashMap<String, Object> map = new HashMap<>();
//自定义查询
map.put("name","wanghang");
map.put("age",18);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
写一个MP的配置类
@Configuration
@MapperScan("com.lyk.mapper")
public class MyBatisPlusConfig {
//分页查询
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor2() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
然后测试
Page(long current, long size)
Page<User> userPage = userMapper.selectPage(page, null); List<User> records = page.getRecords();
page.getRecords()获取分页数据。
@Test
void limitText(){
Page<User> page = new Page<>(1,5);
Page<User> userPage = userMapper.selectPage(page, null);
List<User> records = page.getRecords();
System.out.println("是否有前一页"+page.hasPrevious());
System.out.println("是否有后一页"+page.hasNext());
System.out.println("一页有"+page.getSize()+"条数据");
System.out.println("总页数: "+page.getPages());
System.out.println("总记录数: "+page.getTotal());
for (User record : records) {
System.out.println(record);
}
@Test
void deleteTest1(){
userMapper.deleteById(1423928264693280769L);
}
@Test
void deleteTest2(){
userMapper.deleteBatchIds(Arrays.asList(1423931343090188289L,1423928767514873858L,1423927306227781634L));
}
@Test
void deleteTest3(){
Map map = new HashMap<>();
map.put("name","李永康");
map.put("age","19");
userMapper.deleteByMap(map);
}
给数据库新增一个del字段作为删除标记
给实体类增加这个字段,并标注@TableLogic注解
@TableLogic
private int del;
在配置文件中配置
mybatis-plus.global-config.db-config.logic-delete-field=del
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
逻辑删除特点
- 并不是在数据库层面删除了数据,只是修改了删除标记。
- 在我们之后做查询操作的时候会追加一个条件
del=0
。- 也就是说逻辑删除的数据我们仍然是查询不到的,只有数据库管理员在后台可以查看。
判断全部相等
allEq(Map
params) allEq(Map
params, boolean null2IsNull)
有两个构造器,区别就是null检查。
第一个构造器,对于空判断会用 is null
第二个构造器如果null2IsNull
为true
则和第一个构造器一样
如果为false
,则不对空进行检查
空检查
SELECT id,name,age,email,gmt_create,gmt_modified,version,del FROM user WHERE del=0 AND (age = ? AND email IS NULL)
==> Parameters: 18(Integer)
==> Total: 1
@Test
void allEq(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
Map map = new HashMap();
map.put("age",18);
map.put("name","Jone");
map.put("email",null);
wrapper.allEq(map,T);
userMapper.selectList(wrapper);
}
判断一个条件相等
eq(Children eq(R column, Object val)
构造器接收一个列名,一个参数
@Test
void Eq(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","李永康");
userMapper.selectOne(wrapper);
}
不等于
ne(R column, Object val)
构造器接受一个列名,一个参数
@Test
void ne(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ne("name","");
System.out.println(userMapper.selectList(wrapper));
}
ge(R column, Object val)
构造器接收一个列名,一个参数
@Test
void gt(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age",19);
System.out.println(userMapper.selectList(wrapper));
}
@Test
void ge(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ge("age",19);
System.out.println(userMapper.selectList(wrapper));
}
lt(R column, Object val)
lt(boolean condition, R column, Object val)le同lt
@Test
void lt(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lt("age",20);
System.out.println(userMapper.selectList(wrapper));
}
@Test
void le(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.le("age",20);
System.out.println(userMapper.selectList(wrapper));
}
查找指定范围的
between(R column, Object val1, Object val2)
构造器接收一个列名,两个极值
@Test
void between(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",18,20);
System.out.println(userMapper.selectList(wrapper));
}
结果包含18和20
==> Preparing: SELECT id,name,age,email,gmt_create,gmt_modified,version,del FROM user WHERE del=0 AND (age BETWEEN ? AND ?)
==> Parameters: 18(Integer), 20(Integer)
<== Columns: id, name, age, email, gmt_create, gmt_modified, version, del
<== Row: 1, Jone, 18, [email protected], null, null, 1, 0
<== Row: 2, Jack, 20, [email protected], null, null, 1, 0
<== Row: 3, Tom, 18, [email protected], null, null, 1, 0
<== Total: 3
不查找指定范围内的
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
查找age 不包含[18,20]的
@Test
void notbetween() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notBetween("age", 18, 20);
System.out.println(userMapper.selectList(wrapper));
}
方法 | 构造器 | 对应属性 |
---|---|---|
like | like(R column, Object val) | like("name", "王") —>name like '%王%' |
notLike | notLike(R column, Object val) | notLike("name", "王") —>name not like '%王%' |
likeLeft | likeLeft(R column, Object val) | likeLeft("name", "王") —>name like '%王' |
LikeRight | likeRight(R column, Object val) | likeRight("name", "王") —>name like '王%' |
isNull(R column)
isNull(boolean condition, R column)
判断是否为空
SELECT id,name,age,email,gmt_create,gmt_modified,version,del FROM user WHERE del=0 AND (name IS NULL)
isNotNull(R column)
isNotNull(boolean condition, R column)
判断是否不为空
SELECT id,name,age,email,gmt_create,gmt_modified,version,del FROM user WHERE del=0 AND (name IS NOT NULL)
in(R column, Collection<?> value)
//in("age",{1,2,3})--->age in (1,2,3)
in(R column, Object... values)
//in("age", 1, 2, 3)--->age in (1,2,3)
notIn(boolean condition, R column, Collection<?> value)
//notIn("age",{1,2,3})--->age not in (1,2,3)
notIn(boolean condition, R column, Object... values)
notIn("age", 1, 2, 3)--->age not in (1,2,3)
==> Preparing: SELECT id,name,age,email,gmt_create,gmt_modified,version,del FROM user WHERE del=0 AND (age IN (?,?,?))
==> Parameters: 18(Integer), 2(Integer), 3(Integer)
==> Preparing: SELECT id,name,age,email,gmt_create,gmt_modified,version,del FROM user WHERE del=0 AND (age NOT IN (?,?,?))
==> Parameters: 18(Integer), 2(Integer), 3(Integer)
inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
inSql("age", "1,2,3,4,5,6")
—>age in (1,2,3,4,5,6)
inSql("id", "select id from table where id < 3")
—>id in (select id from table where id < 3)
@Test
void insql(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("age","SELECT age FROM USER WHERE id =3");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
SELECT id,NAME,age,email,gmt_create,gmt_modified,VERSION,del
FROM USER
WHERE
del=0
AND
(age IN (SELECT age FROM USER WHERE id =3))
#先找到 SELECT age FROM USER WHERE id =3 得到结果为 age=18
#然后再进行外层的查询,查询del=0 and age=18
notInSql(R column, String inValue)
notInSql(boolean condition, R column, String inValue)
notInSql("age", "1,2,3,4,5,6")
—>age not in (1,2,3,4,5,6)
notInSql("id", "select id from table where id < 3")
—>id not in (select id from table where id < 3)
@Test
void notinsql(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notInSql("age","select age from id = 3");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
SELECT id,NAME,age,email,gmt_create,gmt_modified,VERSION,del
FROM
USER
WHERE del = 0
AND (
age NOT IN
(SELECT
age
FROM
USER
WHERE id = 3)
)
groupBy(R... columns)
groupBy(boolean condition, R... columns)
分组函数