一、快速入门
1,导入依赖
-
导入mybatis需要的依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency>
2,配置文件
-
配置数据库连接池
spring:
datasource:
url: jdbc:mysql://localhost:3306/mpdb? useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF8&useUnicode=true
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
3,创建表
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`password` varchar(32) NOT NULL,
`age` int NOT NULL,
`tel` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1655401039546839042 DEFAULT CHARSET=utf8mb3;
4,创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
5,继承类
-
mapper层继承类BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
6,测试
/**
* @author 星辰鱼
* @version 1.0
* @date 2023/5/8 10:03
*/
@SpringBootTest
class UserMapperTest {
@Autowired
private UserMapper userMapper;
/**
* 查询
*/
@Test
public void selectListTest(){
// 查询所有
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
}
二、简单的CRUD
1,删除
/**
* 删除
*/
@Test
public void delete(){
// 根据id删除一个
int i = userMapper.deleteById(5);
System.out.println(i);
int i1 = userMapper.deleteBatchIds(Arrays.asList(6, 7, 8));
System.out.println(i1);
}
2,修改
/**
* 修改
*/
@Test
public void update(){
User user = User.builder()
.id(1L)
.name("汤姆")
.password("111111")
.age(888)
.tel("16798761234")
.build();
int i = userMapper.updateById(user);
System.out.println(i);
}
3,增加
/**
* 增加
*/
@Test
public void insert(){
User user = User.builder()
.name("关云长")
.password("123456")
.age(35)
.build();
int insert = userMapper.insert(user);
System.out.println(insert);
}
4,查询
/**
* 查询
*/
@Test
public void selectListTest(){
// 查询所有
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
// 根据id查询
User user = userMapper.selectById(6);
System.out.println(user);
// 根据多个id查询
List<User> users = userMapper.selectBatchIds(Arrays.asList(5, 6, 7, 8));
users.forEach(System.out::println);
}
三、分页查询
1,创建拦截器
1,PaginationInnerInterceptor()
PaginationInnerInterceptor不是spring容器的组件,只能使用new方法
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
// mybatis-plus 的拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
2,测试
@Test
public void pageTest(){
// 分页构造函数(当前页码,每页显示条数)
// pages包含查询的结果
IPage<User> pages = new Page<>(2, 3);
// 添加分页条件
userMapper.selectPage(pages, null);
// 分页记录列表
List<User> records = pages.getRecords();
System.out.println("records = " + records);
// 总行数
long total = pages.getTotal();
System.out.println("total = " + total);
}
四、yml文件简单配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启日志
map-underscore-to-camel-case: true # 开启驼峰映射
type-aliases-package: com.itheima.mp.pojo # 配置别名
mapper-locations: classpath*:/mapper/**/*.xml
五、DQL(数据查询语言)
1,条件查询
核心接口:
QueryWrapper:根据数据库字段名查询
LambdaQueryWrapper:使用Lambda表达式查询
LambdaUpdateWrapper:使用Lambda表达式更新
执行条件判断:
lt:less than 小于
le:less than or equal to 小于等于
eq:equal to 等于
ne:not equal to 不等于
ge:greater than or equal to 大于等于
gt:greater than 大于
多条件关系 and ,or
是否拼接过滤条件的判断
/**
* DQL(数据查询语言)
*/
@Test
public void queryWrapperTest(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// SELECT id,name,password,age,tel FROM user WHERE (name = '汤姆')
queryWrapper.eq("name", "汤姆");
// (age > 15) - 相当于在上面的sql变成了
// gt > , ge >= , lt < , le <=
// SELECT id,name,password,age,tel FROM user WHERE (name = '汤姆' AND age > 15)
queryWrapper.gt("age", 15);
// 当多条件关系为or时
// 相当于拼接了 (OR name LIKE '%j%')
queryWrapper.or().like("tel", "456");
// 【pwd != null】为true时才会拼接后面的条件(OR password = '111111')
String pwd = "111111";
queryWrapper.or().eq(pwd != null, "password", pwd);
/**
* 最终语句
* SELECT
* id, `name`, `password`, age, tel
* FROM `user`
* WHERE (
* `name` = '汤姆' AND age > 15
* OR tel LIKE '%456%' OR PASSWORD = '111111'
* )
*/
List<User> users = userMapper.selectList(queryWrapper);
}
2,投影查询
返回部分列的数据,而不是所有列的数据,可以用投影查询。
让结果集包含指定列
例如:SELECT 列1, 列2, 列3 FROM ...;
LambdaQueryWrapper 比 QueryWrapper 更方便,其他二者每页区别。
/**
* 投影查询
*/
@Test
public void projection(){
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
// SELECT `name` FROM `user`
queryWrapper.select(User::getName)
// GROUP BY `name`
.groupBy(User::getName)
// ORDER BY `name` DESC
.orderByDesc(User::getName);
// 最终结果: SELECT `name` FROM `user` GROUP BY `name` ORDER BY `name` DESC
List<User> users = userMapper.selectList(queryWrapper);
}
//【 错误写法1: 打印的sql中or拼接没有加括号:SELECT COUNT( * ) FROM pm_project WHERE `del_flag` = 0 AND
// ( id = 287 AND `project_status` = '1' OR `project_status` = '2' OR `project_status` = '3' OR `project_status` = '4' AND `del_flag` = '0' );
// LambdaQueryWrapper<PmProject> lqw = Wrappers.lambdaQuery();
// lqw.eq(PmProject::getId,id)
// .eq(PmProject::getProjectStatus, '1').or()
// .eq(PmProject::getProjectStatus, '2').or()
// .eq(PmProject::getProjectStatus, '3').or()
// .eq(PmProject::getProjectStatus, '4')
// .eq(PmProject::getDelFlag, '0');
3,ORM映射
在数据库设计不合理时使用,即数据库表名与字段名与类的类名与属性名不遵循驼峰映射时使用。
建议合理设计数据库。
3.1,映射表名
@TableName("tb_user")在数据库表对应的实体类上注解,表示对应的数据库表的名称
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("tb_user")
public class User {
// ......
}
3.2,映射属性名
@TableField("username")在数据库表对应的实体类上注解,表示对应的数据库表的字段的名称
@TableField("username")
private String name;
3.3 其他
@TableField(select = false) private String tel;表示查询时不查询这个属性对应的字段
@TableField(exist = false) private List<String> str;表示该属性在对应的数据库中没有对应的字段
3.4,举例
/**
* @author 星辰鱼
* @version 1.0
* @date 2023/5/8 10:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("tb_user")
public class User {
private Long id;
@TableField("username")
private String name;
private String password;
private Integer age;
/**
* 表示该字段不参与查询
* SELECT id,username AS name,password,age FROM tb_user WHERE id IN ( ? , ? , ? , ? )
*/
@TableField(select = false)
private String tel;
/**
* 表示该属性在对应的数据库中没有对应的字段
*/
@TableField(exist = false)
private List<String> str;
}
六、DML(数据操纵语言)
1,主键生成策略与主键回填
局部配置:
/** * IdType.ASSIGN_ID : 表示插入数据时,ID自增 * ASSIGN_ID :表示雪花算法生成ID * ASSIGN_UUID(4) : 表示UUID生成ID */ @TableId(type = IdType.ASSIGN_ID) private Long id;
全局配置:
mybatis-plus: # mybatis-plus 全局配置 global-config: db-config: id-type: auto # 配置主键自增 table-prefix: tb_局部配置优先于全局配置
主键会自动回填
2,逻辑删除
一般而言,不建议直接将数据库的字段删除。
所有通常会定义一个逻辑删除字段,通过这个字段的值来判断该数据的状态。
1,在数据库添加逻辑删除字段
2,在实体类使用注解标记表示逻辑删除的属性
/** * 逻辑删除字段 */ @TableLogic private Integer deleted;
3,全局配置
mybatis-plus: global-config: db-config: logic-delete-field: deleted # 表示逻辑删除的成员变量 logic-delete-value: 1 # deleted = 1,表示删除 logic-not-delete-value: 0 # deleted = 1,表示不删除
配置后,删除会将数据库的deleted值变为1
UPDATE tb_user SET deleted=1 WHERE id=? AND deleted=0查询语句也会变化
SELECT id,username AS name,password,age,create_time,deleted FROM tb_user WHERE deleted=0
3,乐观锁
乐观锁有一个关于版本号的字段【version】
修改数据前会先查询当前的【version】字段的值,然后设置对应的条件修改。
修改数据的同时,也会将【version】的值加1
UPDATE tb_user SET username=?, password=?, age=?, version=version + 1 WHERE id=? AND version=?举例说明:
甲乙同时修改一个数据,他们会先获取改数据的version值,然后开始修改。 假设甲先修改,先判断version值,修改后将version值加1。 乙修改时,原本获取的version值与现在的version值不匹配,结果就无法修改。
3.1,实现步骤
1,添加数据库字段
2,增加实体类对应的字段
@Version private Integer version;
3,配置乐观锁拦截器
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ // mybatis-plus 的所有拦截器 MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 乐观锁拦截器 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; }
4,测试
/** * 模拟乐观锁 */ @Test public void locker(){ Long id = 1655493503825780737L; // 1,一先查 User user1 = userMapper.selectById(id); // 2,二后查 User user2 = userMapper.selectById(id); // 3,二先改 user2.setPassword("1234"); userMapper.updateById(user2); // 4,一后改 user1.setPassword("4321"); userMapper.updateById(user1); }
最终二改成功,一改失败