mybatis plus 深入学习 【Base Mapper】的方法 【IService】的方法

本文深入介绍MyBatis Plus的学习内容,涵盖常见注解如@TableName、@TableId,以及LambdaQueryrapper和QueryWrapper的使用,包括动态条件构建、mysql函数嵌入等。还讲解了BaseMapper和IService类的参数及方法,如save、SaveOrUpdate等,助力提升数据库操作效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mybatis plus 深入学习

常见注解

1.@TableName

  • 描述:表名注解,标识实体类对应的表
  • 使用位置:实体类
@TableName("sys_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
属性类型必须指定默认值描述
valueString“”表名
schemaString“”schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMapString“”xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludePropertyString[]{}需要排除的属性名 @since 3.3.1

2.@TableId

  • 描述:主键注解
  • 使用位置:实体类主键字段
@TableName("sys_user")
public class User {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
属性类型必须指定默认值描述
valueString“”主键字段名
typeEnumIdType.NONE指定主键类型

IdType

  • TableId里的值
描述
AUTO数据库 ID 自增
NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUTinsert 前自行 set 主键值
ASSIGN_ID分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
ID_WORKER分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)
UUID32 位 UUID 字符串(please use ASSIGN_UUID)
ID_WORKER_STR分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

LambdaQueryrapper和QueryWrapper

查询的数据和另一张表的某一列有关

假如我想查年龄大于30岁用户的订单信息

int age = 30;
LambdaQueryWrapper<Order> orderWrapper = Wrappers.<Order>lambdaQuery()
        .inSql(Order::getUserId, "SELECT id FROM user where age > " + age);

List<Order> orderList = orderDao.selectList(orderWrapper);

动态条件构建

LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery();
if (StringUtils.isNotBlank(username)) {
    queryWrapper.like(User::getUsername, username);
}
if (minAge != null) {
    queryWrapper.ge(User::getAge, minAge);
}
	// 等价于
    // queryWrapper.ge(minAge != null, User::getAge, minAge);
if (maxAge != null) {
    queryWrapper.le(User::getAge, maxAge);
}

// 可链式
queryWrapper.ge(minAge != null, User::getAge, minAge)
    		.le(maxAge != null, User::getAge, maxAge);
// 也是等价于上面的
List<User> userList = userDao.selectList(queryWrapper);

mysql函数嵌入

假设你有一个实体类User,其中包含了一个日期字段birthDate,你想要查询生日在特定月份的用户,并将生日格式化为"yyyy-MM-dd"格式:


	@Test
    public static void Test2() {
        // 选择要查询的月份,这里假设选择1月
        int selectedMonth = 1;

        LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery()
                .apply("MONTH(birth_date) = {0}", selectedMonth)
                .select(User::getId, User::getName, User::getBirthDate);

        List<User> userList = userDao.selectList(queryWrapper);
        
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        for (User user : userList) {
            String formattedBirthDate = user.getBirthDate().format(formatter);
            System.out.println("User ID: " + user.getId() + ", Name: " + user.getName() + ", Formatted Birth Date: " + formattedBirthDate);
        }
    }

自定义SQL片段构建

有时候,可能需要构建复杂的查询条件,而标准的查询方法不足以满足需求。在这种情况下,可以使用自定义SQL片段来构建查询条件。例如,如果你需要使用OR条件连接多个子条件,可以这样做:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.or(qw -> qw.like("username", "Alice").or().like("username", "Bob"));

List<User> userList = userDao.selectList(queryWrapper);

  • 使用了.or(qw -> ...)来构建自定义的OR条件,然后在其中使用多个.like()条件。这样就创建了一个查询条件,要么用户名包含"Alice"要么包含"Bob"的用户。
LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUserEntity::getStatus, 1)
        .and(i->i.eq(SysUserEntity::getDeptId,3).or().eq(SysUserEntity::getDeptId, 5));
List<SysUserEntity> userEntityList = userService.list(queryWrapper);
  • sql语句user_id,username,password,salt,dept_id,email,mobile,avatar,nick_name,real_name,mini_openid,status,create_user_id,create_time FROM sys_user WHERE (status = ? AND (dept_id = ? OR dept_id = ?))

选择性加载数据

避免不必要的数据加载是提高查询性能的关键。在查询时,只选择那些你实际需要的字段,而不是加载整个实体对象。使用select方法来指定要查询的字段,以减少数据传输和内存占用。

LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        .select(User::getId, User::getName)
        .eq(User::getStatus, 1);

List<User> userList = userDao.selectList(queryWrapper);

分页查询

如果查询结果集很大,使用分页查询来限制返回的数据量。MyBatis-Plus提供了分页查询的支持,可以使用Page类来进行分页操作。

// 1,10 一般是通过前端动态传参进去查找
Page<User> page = new Page<>(1, 10); // 从第一页开始,每页显示10条记录
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        .eq(User::getStatus, 1);

IPage<User> userPage = userDao.selectPage(page, queryWrapper);

BaseMapper

参数说明

类型参数名描述
Tentity实体对象
CollectionentityList实体对象集合
intbatchSize插入批次数量
别名et实体类对象
别名ew查询条件wrapper对象

basemapper类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.baomidou.mybatisplus.core.mapper;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;

public interface BaseMapper<T> extends Mapper<T> {
    int insert(T entity);
T entity = new T(); // 创建实体对象
baseMapper.insert(entity); // 插入数据
    
    int deleteById(Serializable id);
Serializable id = 1L; // 要删除的实体的主键ID=xxx,可序列化的值
baseMapper.deleteById(id); // 删除数据

    int deleteByMap(@Param("cm") Map<String, Object> columnMap);
Map<String, Object> columnMap = new HashMap<>();//创建一个map集合存放符合删除条件需要删除的数据
columnMap.put("name", "zs"); // 设置删除条件,比如name字段等于"zs",将name字段等于"zs"的数据放入创建的map集合
columnMap.put("", "");// 其他条件
baseMapper.deleteByMap(columnMap); // 删除满足条件的数据

    int delete(@Param("ew") Wrapper<T> wrapper);
// 创建Wrapper对象,设置删除条件
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(T::getName, "zs"); // 设置删除条件,比如name字段等于"zs"
baseMapper.delete(wrapper); // 删除满足条件的数据

    int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
Collection<? extends Serializable> idList = Arrays.asList(1L, 2L, 3L); // 要删除的实体的主键ID列表
baseMapper.deleteBatchIds(idList); // 批量删除数据
 
   
    int updateById(@Param("et") T entity);
T entity = new T(); // 创建实体对象
entity.setId(1L); // 设置要更新的实体的主键ID
baseMapper.updateById(entity); // 更新数据

    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T entity = new T(); // 创建实体对象
// 创建Wrapper对象,设置更新条件
LambdaUpdateWrapper<T> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(T::getName, "zs"); // 设置更新条件,比如name字段等于"zs"
baseMapper.update(entity, updateWrapper); // 更新满足条件的数据

    T selectById(Serializable id);
Serializable id = 1L; // 要查询的实体的主键ID
T entity = baseMapper.selectById(id); // 查询数据

    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
Collection<? extends Serializable> idList = Arrays.asList(1L, 2L, 3L); // 要查询的实体的主键ID列表
List<T> entityList = baseMapper.selectBatchIds(idList); // 批量查询数据

    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("name", "zs"); // 设置查询条件,比如name字段等于"zs"
List<T> entityList = baseMapper.selectByMap(columnMap); // 查询满足条件的数据

    T selectOne(@Param("ew") Wrapper<T> queryWrapper);
// 创建Wrapper对象,设置查询条件
LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(T::getName, "zs"); // 设置查询条件,比如name字段等于"zs"
T entity = baseMapper.selectOne(queryWrapper); // 查询满足条件的数据,只查一条数据

    Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
// 创建Wrapper对象,设置查询条件
LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(T::getName, "zs"); // 设置查询条件,比如name字段等于"zs"
int count = baseMapper.selectCount(queryWrapper); // 查询满足条件的数据总数

    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
// 创建Wrapper对象,设置查询条件
LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(T::getAge, 18); // 设置查询条件,比如age字段等于18
List<T> entityList = baseMapper.selectList(queryWrapper); // 查询满足条件的数据列表

    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
// 创建Wrapper对象,设置查询条件
LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(T::getAge, 18); // 设置查询条件,比如age字段等于18
List<Map<String, Object>> mapList = baseMapper.selectMaps(queryWrapper); // 查询满足条件的数据列表,并返回Map集合

    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
// 创建 Wrapper 对象,设置查询条件
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getAge, 18); // 设置查询条件,比如 age 字段等于 18

// 执行查询操作,返回单个字段值列表
List<Object> ageList = userMapper.selectObjs(queryWrapper); // 查询满足条件的 age 字段值列表

    <E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
// 创建Wrapper对象,设置查询条件,分页查询
LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(T::getAge, 18); // 设置查询条件,比如age字段等于18
Page<T> page = new Page<>(1, 10); // 创建分页对象,设置当前页和每页显示数量
IPage<T> pageResult = baseMapper.selectPage(page, queryWrapper); // 分页查询满足条件的数据
List<T> entityList = pageResult.getRecords(); // 当前页的数据列表
long total = pageResult.getTotal(); // 总记录数

    <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
Page<Map<String, Object>> mapPage = userMapper.selectMapsPage(page, queryWrapper);// 根据分页条件查询返回map集合

}

IService类

和mapper层方法大差不差

说明:

  • 通用 Service CRUD 封装IService 接口,进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆,
  • 泛型 T 为任意实体对象
  • 建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类
  • 对象 Wrapper条件构造器

save

// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
参数说明
类型参数名描述
Tentity实体对象
CollectionentityList实体对象集合
intbatchSize插入批次数量
案例
SysUserEntity user = new SysUserEntity();
user.setUsername("zs");
user.setMobile("1234567891");
// user.set...
userService.save(user);


List<SysUserEntity> userEntityList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    SysUserEntity user = new SysUserEntity();
    user.setUsername("zs");
    user.setMobile("1234567891");
    // user.set...
    userEntityList.add(user);
}

userService.saveBatch(userEntityList);
userService.saveBatch(userEntityList, 2); // 设置每个批次传入数据条数
// 该值为2时 10/2 = 5次 插入

SaveOrUpdate

// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
参数说明
类型参数名描述
Tentity实体对象
WrapperupdateWrapper实体对象封装操作类 UpdateWrapper
CollectionentityList实体对象集合
intbatchSize插入批次数量
案例
// 创建一个 SysUserEntity 对象并设置属性
SysUserEntity user = new SysUserEntity();
user.setuserId(3); // 假设库中有id为3的就是更新操作,没有就是插入操作
user.setUsername("zs");
user.setMobile("1234567891");
// 可以继续设置其他属性...

// 调用 saveOrUpdate 方法保存或更新数据,根据主键是否存在来决定是插入还是更新
userService.saveOrUpdate(user);

// 创建多个 SysUserEntity 对象并设置属性
List<SysUserEntity> userEntityList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    SysUserEntity user = new SysUserEntity();
    if (i % 2 == 0) {
        user.setuserId(i); // 假设库中有id为i的就是更新操作,没有就是插入操作
    }
    user.setUsername("zs");
    user.setMobile("1234567891");
    // 可以继续设置其他属性...
    userEntityList.add(user);
}

// 调用 saveOrUpdateBatch 方法批量保存或更新数据,根据主键是否存在来决定是插入还是更新
userService.saveOrUpdateBatch(userEntityList);

// 使用 saveOrUpdateBatch 方法,可以设置每个批次传入数据条数
userService.saveOrUpdateBatch(userEntityList, 2);
// 当 batchSize 设置为 2 时,10/2 = 5 次插入操作

Remove

// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
参数说明
类型参数名描述
WrapperqueryWrapper实体包装类 QueryWrapper
Serializableid主键 ID
Map<String, Object>columnMap表字段 map 对象
Collection<? extends Serializable>idList主键 ID 列表
案例
// 根据 queryWrapper 设置的条件,删除记录
LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUserEntity::getUsername, "zs");
boolean removeResult = userService.remove(queryWrapper);

// 根据 ID 删除
Long idToRemove = 1L; // 假设要删除的记录的 ID 为 1
boolean removeByIdResult = userService.removeById(idToRemove);

// 根据 columnMap 条件,删除记录
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("username", "zs");
boolean removeByMapResult = userService.removeByMap(columnMap);

// 批量删除(根据ID 批量删除)
List<Long> idListToRemove = Arrays.asList(1L, 2L, 3L); // 假设要删除的记录的 ID 列表
boolean removeByIdsResult = userService.removeByIds(idListToRemove);

Update

// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
参数说明
类型参数名描述
WrapperupdateWrapper实体对象封装操作类 UpdateWrapper
Tentity实体对象
CollectionentityList实体对象集合
intbatchSize更新批次数量
案例
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
UpdateWrapper<SysUserEntity> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("username", "zs");
boolean updateResult1 = userService.update(updateWrapper);

// 根据 whereWrapper 条件,更新记录
UpdateWrapper<SysUserEntity> whereWrapper = new UpdateWrapper<>();
whereWrapper.eq("username", "zs");
SysUserEntity updateEntity = new SysUserEntity();
updateEntity.setMobile("1234567890");
boolean updateResult2 = userService.update(updateEntity, whereWrapper);

// 根据 ID 选择修改
SysUserEntity entityToUpdate = new SysUserEntity();
entityToUpdate.setId(1L); // 假设要更新的记录的 ID 为 1
entityToUpdate.setUsername("newZs");
boolean updateByIdResult = userService.updateById(entityToUpdate);

// 根据ID 批量更新
List<SysUserEntity> entityListToUpdate = new ArrayList<>();
// 假设填充了需要更新的实体对象到 entityListToUpdate 中
boolean updateBatchByIdResult1 = userService.updateBatchById(entityListToUpdate);

// 根据ID 批量更新,设置每个批次传入数据条数
boolean updateBatchByIdResult2 = userService.updateBatchById(entityListToUpdate, 2);
// 当 batchSize 设置为 2 时,批量更新操作,每次更新 2 条数据

Get

// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
参数说明
类型参数名描述
Serializableid主键 ID
WrapperqueryWrapper实体对象封装操作类 QueryWrapper
booleanthrowEx有多个 result 是否抛出异常
Tentity实体对象
Function<? super Object, V>mapper转换函数
案例
// 根据 ID 查询
Long userId = 1L; // 假设要查询的记录的 ID 为 1
SysUserEntity userById = userService.getById(userId);

// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
QueryWrapper<SysUserEntity> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("username", "zs")
    		 .last("limmit 1");
SysUserEntity userOne1 = userService.getOne(queryWrapper1);

// 根据 Wrapper,查询一条记录,如果有多个结果是否抛出异常
QueryWrapper<SysUserEntity> queryWrapper2 = new QueryWrapper<>();
queryWrapper2.eq("status", 1);
SysUserEntity userOne2 = userService.getOne(queryWrapper2, true);

// 根据 Wrapper,查询一条记录,并返回 Map 类型结果
QueryWrapper<SysUserEntity> queryWrapper3 = new QueryWrapper<>();
queryWrapper3.eq("age", 25);
Map<String, Object> userMap = userService.getMap(queryWrapper3);

// 根据 Wrapper,查询一条记录,并通过转换函数返回特定类型的结果
QueryWrapper<SysUserEntity> queryWrapper4 = new QueryWrapper<>();
queryWrapper4.eq("gender", "male");
Function<Object, String> mapper = obj -> {
    // 假设转换函数将查询结果转换为字符串类型
    return "User: " + ((SysUserEntity) obj).getUsername();
};
String username = userService.getObj(queryWrapper4, mapper);

List

// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
参数说明
类型参数名描述
WrapperqueryWrapper实体对象封装操作类 QueryWrapper
Collection<? extends Serializable>idList主键 ID 列表
Map<String, Object>columnMap表字段 map 对象
Function<? super Object, V>mapper转换函数

Page

// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
参数说明
类型参数名描述
IPagepage翻页对象
WrapperqueryWrapper实体对象封装操作类 QueryWrapper

Count

// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
参数说明
类型参数名描述
WrapperqueryWrapper实体对象封装操作类 QueryWrapper
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值