SpringBoot整合持久层技术

  1. SpringBoot整合持久层技术
  2. SpringBoot整合JDBCTemplate
  3. SpringBoot整合JDBCTemplate多数据源
  4. SpringBoot整合Mybatis
  5. SpringBoot整合Mybatis多数据源
  6. SpringBoot整合SpringData和Jpa
  7. SpringData Jpa关键字定义查询方法
  8. SpringData Jpa自定义查询SQL
  9. SpringData Jpa自定义数据修改SQL
  10. SpringBoot整合Jpa多数据源


  • SpringBoot整合JDBCTemplate
  • 创建SpringBoot项目,在Dependencies依赖下的SQL中勾选MySQL Driver和JDBC API 在pom中改变数据库的版本号要与自己的匹配 即
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
        <version>5.1.27</version>  //这里的版本号要和实际自己使用的mysql的版本号相同
    </dependency>
    //配一个数据库连接池
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    在application.properties文件中配置数据库连接信息
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.username=root
    spring.datasuourc.password=root
    spring.datasource.url=jdbc:mysq://localhost:3306/zenghao
    创建一个实体类的bean 形如
    public class User {
        private Integer id;
        private String userName;
        private String passWord;
      //  get\set方法
       // ......
    }
    创建一个service
    @Service
    public class UserService{
        @Autowired
        JdbcTemplate jdbcTemplate; //增删改都是update方法
        public Integer addUser(User user){  //添加
          return  jdbcTemplate.update("insert into user(username,password) values(?,?);",
            user.getUsername(),user.getPassword());
        }
        public Integer updateUsernameById(User user) {  //更新
          return  jdbcTemplate update("update user set username = ? where id = ?;",user.getUsername()
            ,user.getId());
        }
        public Integer deleteUserById(Integer id) {  //删除
         return   jdbcTemplate upadte("delete from user where id = ?;",id);
        }
        public List<User> getAllUsers() {  //查询所有,第一种
            return jdbcTemplate.query("select * from user",new RowMapper<User>(){
                @Override
                public User mapRow(ResultSet resultSet,int i)throws SQLException {
                    User user = new USer();
                    int id  = resultSet.getInt("id:);
                    String userName = resultSet.getUserName("username");
                    String passWord = resultSet.getPassWord("password");
                    user.setId(id);
                    user.setUserName(userName);
                    user.setPassword(passWord);
                    return user;
                }
            });
        }
        public List<User> getAllUsers2() {  //查询所有,前提是Bean的属性名和数据库字段名一一对应
            return jdbcTemplate.query("select * from user",
            new BeanPropertyRowMapper<>(User.class));
        }
    }
    创建一个Controller
    @Controller
    public class UserController{
        @AutoWride
        UserService userService;
        
          User user = new User();
        public void contexLoads(){  //添加
            user.setUsername("zhangsan");
            user.setPassword("88888");
            userService.addUser(user);
        }
        public void update(){  //修改
            user.setId(1);
            user.setUsername("lisi");
            userService.updaeUsernameById(user);
        }
        public void del(){   //删除
            userService.deleteUserById(1);
        }
        public void quer1(){  //查询一
           List<User> alluser = userServic.getAllUsers();
           System.out.println(allUser);
        }
         public void quer2(){  //查询二
           List<User> alluser = userServic.getAllUsers2();
           System.out.println(allUser);
        }
    }

    SpringBoot整合jdbcTemplate多数据源整合

项目中存在多个jdbcTemplate,不同的jdbcTemplate操作不同的数据库 在application.properties文件中配置数据库连接信息,配置两个数据源

spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.username=root
spring.datasuourc.one.password=root
spring.datasource.one.url=jdbc:mysq://localhost:3306/zenghao

spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.username=root
spring.datasuourc.two.password=root
spring.datasource.two.url=jdbc:mysq://localhost:3306/zenghao2

 此刻自动化配置失效,就需要手动配置datasource,和jdbcTemplate 创建一个config包 在里面创建一个DataSourceConfig

@Configraution
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix="sping.datasource.one")
    DataSource dsOne(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties(prefix="sping.datasource.two")
    DataSource dsTwo(){
        return DruidDataSourceBuilder.create().build();
    }
}

 创建一个jdbcTemplateConfig

@Configuration
public class JdbcTemplateConfig {
    @Bean
    JdbcTemplate jdbcTemplateOne(@Qualifier("dsOne") DataSource dsOne) {
        return new JdbcTemplate(dsOne);
    }
    @Bean
    JdbcTemplate jdbcTemplateTwo(@Qualifier("dsTwo") DataSource dsTwo) {
        return new JdbcTemplate(dsTwo);
    }
}

 创建一个user对象

Public class User{
    private Integer id;
    private String username;
    private String password;
    //get\set方法
}

在Test目录下写一个测试类

@RunWith(SoringRunner.class)
@SpringBootTest
public class JdbctemplateApplicationTests {
    @Autowired
    @Qualifier("jdbcTemplateOne")  //可以这样指定
    JdbcTemplate jdbcTemplateOne;
    
    @Resource(name = "jdbcTemplateTwo") //也可以这样指定
    JdbcTemplate jdbcTemplateTwo;
    
    @Test
    public void contextLoads(){
        List<User> list1 = jdbcTemplateOne.query("select * from user",
        new BeanPropertyRowMapper<>(User.class));
        List<User> list2 = jdbcTemplateTwo.query("select * from user",
        new BeanPropertyRowMapper<>(User.class));
    }
}

SpringBoot整合MyBatis

创建SpringBoot项目,在Dependencies依赖下的SQL中勾选MySQL Driver和MyBatis Framework 在pom中改变数据库的版本号要与自己的匹配 即

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    <version>5.1.27</version>  //这里的版本号要和实际自己使用的mysql的版本号相同
</dependency>

 配一个数据库连接池

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

在application.properties文件中配置数据库连接信息

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasuourc.password=root
spring.datasource.url=jdbc:mysq://localhost:3306/zenghao

 创建一个实体类(省略) 创建一个Mapper 标记Mapper

@Mapper //第一种直接加注解,但是要在每个Mapper上面都要这样加 
Public interface UserMapper {
    List<User> getAllUser();
};

第二种,在SpringBoot启动类上加包扫描

@SpringBootApplication
@MapperScan(basePackage="org.zenghao.mybatis.mapper)

 (第一种)在resource目录下创建一个org下创建一个zenghao下创建一个mapper目录 在Mapper目录下创建一个xml文件,UserMapper.xml (第二种)和Mapper目录下放在一起,这样使用方便一点,每一个Mapper和对应的mapper.xml 则需要在pom文件下的build中加入

<resource>
    <directory>src/main.java</directory>
    <includes>
        <include>**/*.xml</include>
    </includes>
</resource>

 即可,但是这样创建还是有一个问题,即自己本地运行可以,当打包给别人运行的时候,别的 机器上就默认java目录就是resource目录,则找不到resource目录了,就会报错 此时,可以在下面再补充一句

<resource>
    <directory>src/mian/resources</directory>
</resource>

 即可。 (第三种)若想把xml文件放在resources目录下,创建的其他目录,与java目录不一一对应了, 想把xml文件放在resources目录下新建的一个mapper目录 可以在application.properties中添加

mybatis.mapper-locations=classpath:/mapper/*.xml

 即可。

<mapper namespace="org.zenghao.mybatis.mapper.UserMapper">
    <select id="getAllUser" resultType="org.zenghao.mybatis.bean.User">
        select * from user;
    </select>  
</mapper>

 创建一个测试 类

@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisApplicationTests {
    @AutoWride
    UserMapper userMapper;
    @Test
    public void contextLoads(){
        List<User> allUser = userMapper.getAllUser();
        System.out.println(allUser);
    }
}

SpringBoot中整合mybatis多数据源

在application.properties文件中配置数据库连接信息,配置两个数据源

spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.username=root
spring.datasuourc.one.password=root
spring.datasource.one.url=jdbc:mysq://localhost:3306/zenghao

spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.username=root
spring.datasuourc.two.password=root
spring.datasource.two.url=jdbc:mysq://localhost:3306/zenghao2

 创建一个DataSourceConfig

@Configraution
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix="sping.datasource.one")
    DataSource dsOne(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties(prefix="sping.datasource.two")
    DataSource dsTwo(){
        return DruidDataSourceBuilder.create().build();
    }
}

 创建一个MyBatisConfigOne,第一个数据源 在里面配置sqlSessionFactory和SqlSessionTemplate

@Configuration
@MapperScan(basePackages="org.zenghao.mybatis.mapper1",
sqlSessionFactoryRef="sqlSessionFactory1",
sqlSessionTemplateRef="sqlSessionTemplate1")
public class MyBatisConfiOne {
    @Resource(name="dsOne")  //首先把resource注入进来
    DataSource dsOne;
    
    @Bean  //注入为Bean
    SqlSessionFactory sqlSessionFactory1() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        try{
            bean.setDataSource(dsOne);
            return bean.getObject();
        }catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    @Bean
    SqlSessionTemplate sqlSessionTemplate1() {
        return new SqlSessionTemplate(sqlSessionFactory1());
    }    
}

 创建一个MyBatisConfigTwo,第二个数据源 在里面配置sqlSessionFactory和SqlSessionTemplate

@Configuration
@MapperScan(basePackages="org.zenghao.mybatis.mapper2",
sqlSessionFactoryRef="sqlSessionFactory2",
sqlSessionTemplateRef="sqlSessionTemplate2")
public class MyBatisConfiOne {
    @Resource(name="dsTwo")  //首先把resource注入进来
    DataSource dsTwo;
    
    @Bean  //注入为Bean
    SqlSessionFactory sqlSessionFactory2() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        try{
            bean.setDataSource(dsTwo);
            return bean.getObject();
        }catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    @Bean
    SqlSessionTemplate sqlSessionTemplate2() {
        return new SqlSessionTemplate(sqlSessionFactory2());
    }    
}

 创建一个User实体类(略) 创建两个Mapper

public interface UserMapper1 {
    List<User> getAllUsers();
}
public interface UserMapper2 {
    List<User> getAllUsers();
}

 分别创建各自的xml 文件

<mapper namesqpce="org.zenghao.mybatis.mapper.UserMapper1">
    <select id="getAllUsers" resultType="org.zenghao.mybatis.bean.User">
        select * from user;
     </select>
</mapper>
<mapper namesqpce="org.zenghao.mybatis.mapper.UserMapper2">
    <select id="getAllUsers" resultType="org.zenghao.mybatis.bean.User">
        select * from user;
     </select>
</mapper>

 创建一个测试 类

@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisApplicationTests {
    @AutoWride
    UserMapper1  userMapper1;
     @AutoWride
    UserMapper2  userMapper2;
    @Test
    public void contextLoads(){
        List<User> allUser1 = userMapper1.getAllUsers();
        System.out.println(allUser1);
         List<User> allUser2 = userMapper2.getAllUsers();
        System.out.println(allUser2)
    }
}                

 


SpringData和Jpa简介

Jpa,用于持久化的API 标准的ORM规范,不是ORM框架,应为并未提供ORM实现。使得应用程序统一的方式访问持久层 是Hibernate的一个抽象(就像JDBC和JDBC驱动的关系) Hibernate是实现:Hibernate除了作为ORM框架外,它也是一种JPA实现 从功能上来说,JPA是Hibernate功能的一个子集。 SpringData是Spring的一个子项目,致力于减少数据访问层(DAO)的开发量


  • SpringBoot整合SpringData Jpa
  • Dependencies选择MySQL Driver和Spring Data JPA 在Pom文件中加入druid和mysql依赖
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
 </dependency>
 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <scope>runtime</scope>
     <version>5.1.27</version>
 </dependency> 
 

 在application.properties配置数据源

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username-root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/zenghao

spring.jpa.show-sql=true  //打印sql
spring.jpa.database=mysql  //指定数据库
spring.jpa.database-platform=mysql
spring.jpa.hibernate.ddl-auto=update  //每次启动校验数据库表是否存在,不存在,创建,存在,更新
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect //指定方言

 创建一个实体类Book 实体类上加注解@Entity(name="t_book")//创建的表的名字

@Entity(name="t_book")
public class Book {
    @Id  //指定id为主键
    @GeneratedValue(strategy=GenerationType.IDBNTITY)  //设置id的自增长策略
    private Interger id;
    @Column("....")  //定义数据库中该字段的详细信息
    private String name;
    private String author;
   // get/set()
    //......
}

 创建一个Dao,BookDao,定义好就可以,里面不需要任何操作,会自动识别到容器里面

//启动项目自动创建t_book表
public interface BookDao extends JpaRepository<Book,Integer> {
}

创建一个Test类,

@AutoWired
BookDao bookDao;
@Test
public void contextLoads(){
    Book book = new Book();
    book.setName("三国演绎");
    book.setAuthor("罗贯中");
    bookDao.save(book); //向t_book中插入一条数据
}
@Test
public void update() {
     Book book = new Book();
     book.setName("sanguoyanyi");
     book.setAuthoe("luoguanzhong");
     book.setId(1);
     bookDa0.saveAndFlush(book);//t_book中根据Id更新数据
}
@Test
public void del(){
    bookDao.deleteById(1) //删除t_book中Id为1d的数据
}
@Test
public void find1(){
   Optioonal<Book> byId =  bookDao.findById(2);
   System.out.println(byId.get());  //根据Id查询
   List<Book> all = bookDao.findAll();
   System.out.println(all);  //查询所有
}
@Test  //可指定查询方向,根据id倒叙查询
public void find2(){
    List<Book> list  = bookDap.findAll(new Short( Sort.Direction.DESC,"id"));
    System.out.println(list);
}
@Test  //分页查询
public void find3(){
   Pageable pageable =Pageable.of(page:0,size:2);  //0表示从第一页开始,size表示一页有两条数据
     Page<Book> page = bookDao.findAll(pageable);
     System.out.println(page.getNumberOfElements());//当前页记录数
      System.out.println(page.getTotalElements());//总记录数
      System.out.println(page.getSize());//获取每页的记录数
      System.out.println(page.getTotalPages());//获取总页数
      System.out.println(page.getContent());//查询结果哦
      System.out.println(page.getNumber());//当前页,从0开始计数
      System.out.println(page.isFirst());//是否为首页
      System.out.println(page.isLast()); //是否为尾页
}
  • SpringData Jpa自定义查询方法,接上
  • 在BookDao接口里面定义自己的方法
public interface BookDao extends JpaRepostory<Book,Integer> {
    Book findBookById(Integer id);  //自定义根据id查找
    
}
@Test
public void find4(){
    Book book = bookDao.findBookById(2);
    System.out.println(book);
}

  • SpringData Jpa自定义查询SQL
  • 在BookDao接口里面定义自己的方法
public interface BookDao extends JpaRepostory<Book,Integer> {
   @Query(value="select * from t_book where id=(select max(id) from t_book)"
   ,nativeQuery=true)  //这样定义的查询就位原生查询语句
     Book getMaxIdBook();  //查询id最大的一本书   
}
@Test
public void find5(){
    Book book = bookDao.getMaxIdBook();
    System.out.println(book);
}

Spring Data Jpa自定义数据修改

public interface BookDao extends JpaRepostory<Book,Integer> {
  @Query(value="insert into t_boo(name,author)values(?1,?2)",nativeQuery=true)
  @Modifying  //必须
  @Transactional  //必须
   Integer addBook(String name,String author);
  //或者
  @Query(value="insert into t_boo(name,author)values(:name,:author)",nativeQuery=true)
    @Modifying
    @Transactional
   Integer addBook2(@Praram("name")String name,@Praram("author")String author);


}

@Test
public void insert1(){
   bookDao.addBook("朝花夕拾","鲁迅");
   bookDao.addBook2("呐喊","鲁迅");
}

 


SpringBoot整合Jpa多数据源

 锁定数据库驱动版本 添加druid数据库连接池,同上 在application.properties添加配置,同上 在application.properties配置数据源

spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.username-root
spring.datasource.one.password=root
spring.datasource.one.url=jdbc:mysql://localhost:3306/zenghao?useUnicode=true&characterEncoding=UTF-8

spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.username-root
spring.datasource.two.password=root
spring.datasource.two.url=jdbc:mysql://localhost:3306/zenghao?useUnicode=true&characterEncoding=UTF-8

spring.jpa.properties.show-sql=true  //打印sql
spring.jpa.properties.database=mysql  //指定数据库
spring.jpa.properties.database-platform=mysql
spring.jpa.properties.hibernate.ddl-auto=update  //每次启动校验数据库表是否存在,不存在,创建,存在,更新
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect //指定方言

 创建一个Book实体

@Entity(name="t_book")
public class Book {
    @Id
    @GeneratedValue(startegy=GenerationType.IDENTYITY)
    private Integer id;
    private String name;
    private String author
  //  get/set()
 //   .....
}

 创建一个config目录下创建DataSourceConfig

@Configuration
public class DataSourceConfig{
    @Bean
    @Primary  //表示有多个数据源的时候优先使用它
    @ConfigurationProperties(prefix="spring.datasource.one")
    Datashorce dsOne(){
        return DruidDataSourceBuilder.create().build();
    }
    
    @Bean
    @ConfigurationProperties(prefix="spring.datasource.two")
    Datasource dsTwo(){
        return DruidDataSourceBuilder.create().build();
    }
}

 创建两个Jpa配置

@Configuration
@EnableJpaRepositories(basePackages="org.zenghao.jpa.dao1",
                entityManagerFactoryRef="localContainerEntityManagerFactoryBean1",
                transactionManagerRef="platformTransactionManager1")
public class JpaConfig1 {
    @Autowired
    @Quallifier("dsOne")
    DataSource dsOne;
    
    @AutoWired
    JpaProperties jpaProperties;
    
    @Bean
    @Primary  //表示有多个数据源的时候,优先使用它
    LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean1(EntityManagerFactoryBuild builder) {
        return builder.dataSource(dsOne)
                .properties(jpaProperties.getProperties())
                .persistenceUnit("pul")
                .packages("org.zenghao.jpa.bean")
                .build();
    }
    Bean
    platformTransactionManager platformTransactionManager1(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(lcoalContainerEntityManagerFactoryBean(builder).getObject());
    }
}

 至此第一个Jpa就配置好了,第二个和第一个是一样的配置

@Configuration
@EnableJpaRepositories(basePackages="org.zenghao.jpa.dao2",
                entityManagerFactoryRef="localContainerEntityManagerFactoryBean2",
                transactionManagerRef="platformTransactionManager2")
public class JpaConfig2 {
    @Autowired
    @Quallifier("dsTwo")
    DataSource dsTwo;
    
    @AutoWired
    JpaProperties jpaProperties;
    
    @Bean
    LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean2(EntityManagerFactoryBuild builder) {
        return builder.dataSource(dsTwo)
                .properties(jpaProperties.getProperties())
                .persistenceUnit("pu2")
                .packages("org.zenghao.jpa.bean")
                .build();
    }
    Bean
    platformTransactionManager platformTransactionManager2(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(lcoalContainerEntityManagerFactoryBean(builder).getObject());
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot持久层主要是通过整合Spring Data JPA来实现的。在SpringBoot中,默认支持的数据源有org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource以及BasicDataSource等。通过Spring Data JPA,我们可以快速实现基本的增删改查操作,以及自定义查询方法。 以下是使用SpringBoot整合Spring Data JPA实现单表CRUD的步骤: 1. 配置数据源:在application.properties或application.yml文件中配置数据源相关信息,包括数据库连接信息、用户名和密码等。 2. 创建实体类:创建对应数据库表的实体类,并使用注解定义表名、字段名、关联关系等。 3. 创建Repository接口:创建继承自JpaRepository的Repository接口,并定义需要的查询方法。 4. 编写业务逻辑:根据需要,编写Service层的接口和实现类,处理业务逻辑,调用Repository接口中的方法进行数据库操作。 5. 注入依赖:使用@Autowired注解将Repository接口和Service实例注入到Controller中。 6. 编写Controller:编写控制器类,处理HTTP请求,调用Service层的方法,并返回结果。 通过以上步骤,我们可以在SpringBoot中快速搭建持久层,实现对数据库的操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [springboot整合持久层](https://blog.csdn.net/weixin_41359273/article/details/120465426)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【SpringBootSpringBoot——整合持久层技术](https://blog.csdn.net/lht964249279/article/details/122749615)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值