一、MyBatisPlus
(1)使用MyBatisPlus的基本操作步骤
①引入MybatisPlus依赖,代替Mybatis依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
②定义Mapper接口并继承BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
(2)常见注解
①MybatisPlus是如何获取实现CRUD的数据库表信息的?
MyBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
默认类名驼峰转下划线作为表名,名为id的字段作为主键,变量名驼峰转下划线作为表的字段名。
②常用注解:
@TableName:用来指定表名。
@TableId:用来指定表中的主键字段信息
@TableField:用来指定表中的普通字段信息
③IdType(枚举)的常见类型:
AUTO:数据库自增长
ASSIGN_ID:分配ID,接口IdentifierGenerator的方法nextId来生成id,默认实现类为DefaultIdentifierGenerator雪花算法
INPUT:通过set方法自行输入
④使用@TableField的常见场景:
成员变量名与数据库字段名不一致。
成员变量名以is开头,且为布尔值。
成员变量名与数据库关键字冲突。
成员变量不是数据库字段。
(3)常见配置
mybatis-plus:
type-aliases-package: com.itheima.mp.domain.po # 别名扫描包
mapper-locations: "classpath*:/mapper/**/*.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 # 更新策略:只更新非空字段
二、核心功能
(1)条件构造器
①QueryWrapper和LambdaQueryWrapper通常用来构建select、delete、update的where条件部分。
@Test
void testQueryWrapper(){
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.select("id","username","info","balance")
.like("username","o")
.ge("balance",1000);
//2.查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
②UpdateWrapper和LambdaUpdateWrapper通常只有在set语句比较特殊才使用。
@Test
void testUpdateWrapper() {
List<Long>ids=new ArrayList<Long>();
ids.add(1L);
ids.add(2L);
ids.add(4L);
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
.setSql("balance=balance-200")
.in("id",ids);
userMapper.update(null, wrapper);
}
③尽量使用LambdaQueryWrapper和LambdaUpdateWrapper,避免硬编码。
@Test
void testLambdaQueryWrapper(){
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.select(User::getId,User::getUsername,User::getInfo,User::getBalance)
.like(User::getUsername,"o")
.ge(User::getBalance,1000);
//2.查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
(2)自定义SQL
我们可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。
①基于Wrapper构建where条件
@Test
void testCustomSqlUpdate(){
// 1.更新条件
List<Long>ids=new ArrayList();
ids.add(1L);
ids.add(2L);
ids.add(4L);
int amount=200;
// 2.定义条件
QueryWrapper<User>wrapper=new QueryWrapper<User>().in("id" ,ids);
// 3.调用自定义的SQL方法
userMapper.updateBalanceByIds(wrapper,amount);
}
②在Mapper方法参数中用Param注解声明Wrapper变量名称,必须是ew
void updateBalanceByIds(@Param("ew") QueryWrapper<User> wrapper,@Param("amount") int amount);
③自定义SQL,并使用Wrapper条件
<update id="updateBalanceByIds">
update tb_user set balance=balance-#{amount} ${ew.customSqlSegment}</update>
(3)MP的Service接口使用流程
①自定义Service接口继承IService接口
public interface IUserService extends IService<User> {}
②自定义Service实现类,实现自定义接口并继承ServiceImpl类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{}
(4)iService开发基础业务接口
@Api(tags = "用户管理接口")
@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
private final IUserService userService;
// 新增
@ApiOperation("新增用户接口")
@PostMapping
public void save(@RequestBody UserFormDTO userDTO){
// 1.将DTO拷贝到PO
User user = BeanUtil.copyProperties(userDTO, User.class);
// 2.新增
userService.save(user);
}
(5)iService开发复杂业务接口
①控制层:
@ApiOperation("扣减用户余额接口")
@PutMapping("/{id}/deduction/{money}")
public void deductBalance(
@ApiParam("用户id") @PathVariable("id")Long id,
@ApiParam("扣减的金额") @PathVariable("money")Integer money) {
userService.deductBalance(id,money);
}
②业务层:
void deductBalance(Long id, Integer money);
@Override
public void deductBalance(Long id, Integer money) {
// 1.查询用户
User user = getById(id);
// 2.校验用户状态
if (user==null||user.getStatus()==2){
throw new RuntimeException("用户状态异常!");
}
// 3.校验余额是否充足
if(user.getBalance()<money){
throw new RuntimeException("用户余额不足!");
}
// 4.扣减余额
baseMapper.deductBalance(id,money);
}
③数据层:
@Update("update tb_user set balance=balance-#{money} where id=#{id}")
void deductBalance(@Param("id") Long id, @Param("money") Integer money);
(6)IService的Lambda查询
@ApiOperation("根据复杂条件查询用户接口")
@GetMapping("/list")
public List<UserVO> queryUsers(UserQuery query){
// 1.查询用户PO
List<User> users = userService.queryUsers(query.getName(),query.getStatus(),query.getMaxBalance(),query.getMinBalance());
// 2.把PO拷贝到VO
return BeanUtil.copyToList(users, UserVO.class);
}
List<User> queryUsers(String name, Integer status, Integer maxBalance, Integer minBalance);
@Override
public List<User> queryUsers(String name, Integer status, Integer maxBalance, Integer minBalance) {
List<User> users = lambdaQuery().like(name != null, User::getUsername, name)
.like(status != null, User::getStatus, status)
.ge(minBalance != null, User::getBalance, minBalance)
.le(maxBalance != null, User::getBalance, maxBalance)
.list();
return users;
}
(7)IService的Lambda更新
@ApiOperation("扣减用户余额接口")
@PutMapping("/{id}/deduction/{money}")
public void deductBalance(
@ApiParam("用户id") @PathVariable("id")Long id,
@ApiParam("扣减的金额") @PathVariable("money")Integer money) {
userService.deductBalance(id,money);
}
void deductBalance(Long id, Integer money);
@Override
@Transactional
public void deductBalance(Long id, Integer money) {
// 1.查询用户
User user = getById(id);
// 2.校验用户状态
if (user==null||user.getStatus()==2){
throw new RuntimeException("用户状态异常!");
}
// 3.校验余额是否充足
if(user.getBalance()<money){
throw new RuntimeException("用户余额不足!");
}
// 4.扣减余额
// baseMapper.deductBalance(id,money);
int remainBalance=user.getBalance()-money;
lambdaUpdate().set(User::getBalance,remainBalance)
.set(remainBalance==0,User::getStatus,2)
.eq(User::getId,id)
.eq(User::getBalance,user.getBalance())//乐观锁,避免多线程操作
.update();
}