这里写目录标题
- MyBatisPlus基础
- 1. MyBatisPlus使用
- 1.1 引入MyBatisPlus依赖
- 1.2 Mapper接口继承BaseMapper<T>
- 1.3 测试
- 2. MyBatisPlus注解
- 2.1 常见注解
- 2.2 IdType枚举
- 2.3 @TableField使用场景
- 3. MyBatisPlus配置
- 4. 核心功能
- 4.1 条件构造器
- 4.1.1 基于QueryWrapper查询
- 4.1.2 基于QueryWrapper更新
- 4.1.3 基于UpdateWrapper更新
- 4.1.4 LambdaQueryWrapper
- 4.2 自定义SQL
- 4.3 Service接口
- 4.3.1 CRUD
- 4.3.2 Restful风格编写Controller
- 4.3.3 Lambda
MyBatisPlus基础
MyBatis-Plus:
MyBatis最佳拍档,只做增强不做改变,为简化开发、提高效率而生。
特性:
- 只做增强不做改变,引入它不会对现有工程产生影响,如丝般润滑;
- 只需简单配置,即可快速进行表单CRUD操作,从而节省大量时间;
- 代码生成、自动分页、逻辑删除、自动填充、拦截器等功能一应俱全;
- 连续5年获得开源中国年度最佳开源项目特殊荣誉,Github累计16K Star;
1. MyBatisPlus使用
1.1 引入MyBatisPlus依赖
pom.xml
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version>
</dependency>
如果是Springboot3
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.9</version>
</dependency>
1.2 Mapper接口继承BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {//不用写单表增删改查方法,直接继承baseMapper方法
// public void insertUser(User user);
// public User selectUserById(Integer id);
}
1.3 测试
@SpringBootApplication
public class MybatisplusDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(MybatisplusDemoApplication.class, args);UserMapper userMapper = context.getBean(UserMapper.class);User user = userMapper.selectById(1);System.out.println(user);}}
2. MyBatisPlus注解
MP约定:
- 类名驼峰转下划线作为表名
- 名为id的字段作为主键
- 变量名驼峰转下划线作为表的字段名
2.1 常见注解
MybatisPlus中比较常用的几个注解如下:
- @TableName:用来指定表名
- @TableId:用来指定表中的主键字段信息
- @TableField:用来指定表中的普通字段信息
2.2 IdType枚举
- AUTO:数据库自增长
- INPUT:通过set方法自行输入
- ASSIGN_ID:分配 ID,接口IdentifierGenerator的方法nextId来生成id,默认实现类为DefaultIdentifierGenerator雪花算法
2.3 @TableField使用场景
- 成员变量名与数据库字段名不一致
- 成员变量名以is开头,且是布尔值
- 成员变量名与数据库关键字冲突
- 成员变量不是数据库字段
3. MyBatisPlus配置
MyBatisPlus的配置项继承了MyBatis原生配置和一些自己特有的配置:
mybatis-plus:type-aliases-package: com.feng.mp.domain.po # 别名扫描包mapper-locations: "classpath*:/mappers/**/*.xml" # Mapper.xml文件地址,默认值configuration:map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射cache-enabled: false # 是否开启二级缓存global-config:db-config:id-type: assign_id # id为雪花算法生成update-strategy: not_null # 更新策略:只更新非空字段
4. 核心功能
4.1 条件构造器
4.1.1 基于QueryWrapper查询
@Testpublic void testQueryWrapper(){//1、构造查询条件QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("id","username","balance").like("username","o").ge("balance",1000);//2、执行查询List<User> users = userMapper.selectList(queryWrapper);System.out.println(users);}
Preparing: SELECT id,username,balance FROM user WHERE (username LIKE ? AND balance >= ?)
Parameters: %o%(String), 1000(Integer)
4.1.2 基于QueryWrapper更新
@Testvoid testUpdateByQueryWrapper() {User user = new User();user.setBalance(1000);QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("username","Jack");userMapper.update(user, queryWrapper);}
Preparing: UPDATE user SET balance=? WHERE (username = ?)
Parameters: 1000(Integer), Jack(String)
4.1.3 基于UpdateWrapper更新
@Test
void testUpdateWrapper(){List<Long> userList = List.of(1L,2L,4L);UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>();updateWrapper.setSql("balance = balance - 200").in("id",userList);userMapper.update(null,updateWrapper);
}
Preparing: UPDATE user SET balance = balance - 200 WHERE (id IN (?,?,?))
Parameters: 1(Long), 2(Long), 4(Long)
4.1.4 LambdaQueryWrapper
避免硬编码
public void testLambdaQueryWrapper(){//1、构造查询条件LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.select(User::getId,User::getUsername,User::getBalance).like(User::getUsername,"o").ge(User::getBalance,1000);//2、执行查询List<User> users = userMapper.selectList(lambdaQueryWrapper);System.out.println(users);
}
Preparing: SELECT id,username,balance FROM user WHERE (username LIKE ? AND balance >= ?)
Parameters: %o%(String), 1000(Integer)
4.2 自定义SQL
自定义接口方法
@Mapper
public interface UserMapper extends BaseMapper<User> {//两个参数都需要添加@Param()注解public void updateBalanceByIds(@Param("ew") LambdaQueryWrapper<User> lambdaQueryWrapper, @Param("amount") int amount);}
编写UserMapper.xml映射文件
<mapper namespace="com.feng.mybatisplusdemo.dao.UserMapper"><update id="updateBalanceByIds" >update user set balance = balance + #{amount} ${ew.customSqlSegment}</update>
</mapper>
测试类
@Test
public void testCustomSqlUpdate(){List<Long> list = List.of(1L,2L,3L);int amount = 200;//1.构建条件LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>();lambdaQueryWrapper.in(User::getId,list);//2.自定义SQL方法调用userMapper.updateBalanceByIds(lambdaQueryWrapper,amount);
}
4.3 Service接口
MybatisPlus提供了IService接口,实现增删改查的操作,并提供了IService接口的实现类ServiceImpl<T extend BaseMapper,T extend Object>
我们需要使用时,在自定义接口IUserService中继承MP提供的IService接口;在我们的接口实现类UserServiceImpl中继承MP提供的ServiceImpl并实现我们自己的接口就可以
save
:新增remove
:删除update
:更新get
:查询单个结果list
:查询集合结果count
:计数page
:分页查询
4.3.1 CRUD
新增
save
是新增单个元素saveBatch
是批量新增saveOrUpdate
是根据id判断,如果数据存在就更新,不存在则新增saveOrUpdateBatch
是批量的新增或修改
删除
removeById
:根据id删除removeByIds
:根据id批量删除removeByMap
:根据Map中的键值对为条件删除remove(Wrapper<T>)
:根据Wrapper条件删除
修改
updateById
:根据id修改update(Wrapper<T>)
:根据UpdateWrapper
修改,Wrapper
中包含set
和where
部分update(T,Wrapper<T>)
:按照T
内的数据修改与Wrapper
匹配到的数据updateBatchById
:根据id批量修改
查get
getById
:根据id查询1条数据getOne(Wrapper<T>)
:根据Wrapper
查询1条数据getBaseMapper
:获取Service
内的BaseMapper
实现,某些时候需要直接调用Mapper
内的自定义SQL
时可以用这个方法获取到Mapper
查list
listByIds
:根据id批量查询list(Wrapper<T>)
:根据Wrapper条件查询多条数据list()
:查询所有
count
count()
:统计所有数量count(Wrapper<T>)
:统计符合Wrapper
条件的数据数量
自定义接口
/*
* 自定义接口实现MyBatisPlus提供的IService接口
* */
public interface IUserService extends IService<User> {
}
自定义实现类
/*** @description: User接口实现类* 继承MyBatisPlus提供的ServiceImpl实现类,<T extend BaseMapper,T extend Object>* 实现我们自己的自定义接口IUserService**/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
测试类
@SpringBootTest
@RunWith(SpringRunner.class)
public class IUserServiceTest {@Autowiredprivate IUserService userService;/*保存*/@Testpublic void testSave(){User user = new User();user.setUsername("zhangsan");user.setPassword("123456");user.setPhone("18888888888");user.setInfo("{\"age\": 22, \"intro\": \"有为青年\", \"gender\": \"male\"}");user.setStatus(1);user.setBalance(10000);user.setCreateTime(new Date());user.setUpdateTime(new Date());userService.save(user);}/*查询*/@Testpublic void testQuery(){userService.listByIds(List.of(1L,2L,3L)).forEach(System.out::println);}
}
4.3.2 Restful风格编写Controller
package com.feng.mybatisplusdemo1.contraller;import cn.hutool.core.bean.BeanUtil;
import com.feng.mybatisplusdemo1.dto.UserFormDTO;
import com.feng.mybatisplusdemo1.po.User;
import com.feng.mybatisplusdemo1.service.IUserService;
import com.feng.mybatisplusdemo1.vo.UserVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** @program: mybatisplus-demo1* @description: UserController* @author: FF* @create: 2024-12-22 23:01**/
@Tag(name = "用户Controller",description = "用户Controller-description")
//@RequiredArgsConstructor
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService iUserService;@PostMapping@Operation(summary = "新增用户接口", description = "新增用户接口description")public void saveUser(@Parameter(description = "UserDto")@RequestBody UserFormDTO userFormDTO){System.out.println("==================="+userFormDTO);//将DTO转换为POUser user = BeanUtil.copyProperties(userFormDTO, User.class);iUserService.save(user);}@DeleteMapping("{id}")@Operation(summary = "删除用户ByID",description = "通过用户ID删除用户记录")public void deleteUserById(@Parameter(description = "id") @PathVariable("id") Long id){iUserService.removeById(id);}@GetMapping("{id}")@Operation(summary = "查找用户ById",description = "通过ID查找用户,并返回VO")public UserVO getUserById(@Parameter(description = "id") @PathVariable("id") Long id){User user = iUserService.getById(id);//user转userVOUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);System.out.println(userVO);return userVO;}//根据用户ID集合查询用户集@GetMapping@Operation(summary = "根据用户ID集合查询用户集",description = "根据ID查询用户集userVO list")public List<UserVO> getUserList(@Parameter(description = "用户ID集合") @RequestParam("ids") List<Long> ids){List<User> list = iUserService.listByIds(ids);List<UserVO> userVOS = BeanUtil.copyToList(list, UserVO.class);return userVOS;}
}
4.3.3 Lambda
LambdaQuery
@Data
@JsonSerialize
@Schema(description = "用户查询实体类")
public class UserQuery {@Schema(description = "用户名关键字")private String name;@Schema(description = "用户状态:1-正常,2-冻结")private Integer status;@Schema(description = "余额最小值")private Integer minBalance;@Schema(description = "余额最大值")private Integer maxBalance;
}
@GetMapping("/list")@Operation(summary = "lambdaQuery",description = "复杂条件查询")public List<UserVO> lambdaQuery(@Parameter(description = "UserQuery") @ModelAttribute UserQuery userQuery){System.out.println("=============="+userQuery.getName());List<User> userList = iUserService.lambdaQuery().like(null != userQuery.getName(), User::getUsername, userQuery.getName()).eq(null != userQuery.getStatus(), User::getStatus, userQuery.getStatus()).gt(null != userQuery.getMinBalance(), User::getBalance, userQuery.getMinBalance()).le(null != userQuery.getMaxBalance(), User::getBalance, userQuery.getMaxBalance()).list();List<UserVO> userVOS = BeanUtil.copyToList(userList, UserVO.class);System.out.println(userVOS);return userVOS;}
lambdaQuery方法中除了可以构建条件,还需要在链式编程的最后添加一个list(),这是在告诉MP我们的调用结果需要是一个list集合。这里不仅可以用list(),可选的方法有:
- .one():最多1个结果
- .list():返回集合结果
- .count():返回计数结果
MybatisPlus会根据链式编程的最后一个方法来判断最终的返回结果
LambdaUpdate
//根据id修改用户余额,如果扣减后余额为0,则将用户status修改为冻结状态(0)@PutMapping@Operation(summary = "根据ID修改用户金额,并更新状态")@Transactionalpublic void lambdaUpdateTest(Long id, Integer money){User user = iUserService.getById(id);//根据ID查询用户账户信息int remainBalance = user.getBalance() - money;//扣减后余额int flag = 0;//冻结if(null == user || 0 == user.getStatus()){throw new RuntimeException("账户状态异常");} else if (user.getBalance() < money) {throw new RuntimeException("账户余额不足");}iUserService.lambdaUpdate().set(User::getBalance, remainBalance).set(remainBalance == flag,User::getStatus, 0).eq(User::getId, id).eq(User::getBalance, user.getBalance())//乐观锁.update();}