Mybatis入门

22 篇文章 0 订阅
4 篇文章 0 订阅

1.简介

1-1什么是mybatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)

如何使用mybatis?

  • github仓库下载
  • maven
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
  • mybatis中文文档

1-2.持久层简介

数据持久化
持久化:就是将程序的数据在持久状态和瞬时状态时转换的过程
内存:断电即失—内存转换到硬盘就是持久化
数据库(JDBC)IO文件持久化(由于IO浪费资源,所以诞生了数据库)
为什么需要持久化
持久化技术封装了数据访问细节,为大部分业务逻辑提供面向对象的API。
● 通过持久化技术可以减少访问数据库数据次数,增加应用程序执行速度;
● 代码重用性高,能够完成大部分数据库操作;
● 松散耦合,使持久化不依赖于底层数据库和上层业务逻辑实现,更换数据库时只需修改配置文件而不用修改代码。
持久层
Dao层,Service层,Controller层

  • 完成持久化的代码块
  • 层界限十分明显
    [quote]狭义的理解: “持久化”仅仅指把域对象永久保存到数据库中;广义的理解,“持久化”包括和数据库相关的各种操作(持久化就是将有用的数据以某种技术保存起来,将来可以再次取出来应用,数据库技术,将内存数据一文件的形式保存在永久介质中(磁盘等)都是持久化的例子.)。
    ● 保存:把域对象永久保存到数据库。
    ● 更新:更新数据库中域对象的状态。
    ● 删除:从数据库中删除一个域对象。
    ● 加载:根据特定的OID,把一个域对象从数据库加载到内存。
    ● 查询:根据特定的查询条件,把符合查询条件的一个或多个域对象从数据库加载内在存中。

1-3.为什么需要mybatis

mybatis做好了自动封装数据对象这件事
实际上在mybatis的应用场景里面,开发者要的就是自动封装,把sql查询结果转化为指定的java对象,这就足够了。

  • 简单方便
  • 减少冗余,解耦合
  • 自动化
  • 容易上手
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql。
  • 使用的人(公司)多
    技术没有高低之分,关键还在个人。

2.第一个mybatis程序

思路:搭建环境–>导入mybatis–>编写代码–>运行

2-1.搭建环境

搭建数据库
用sql语句或者可视化工具创建数据库,在这里建议用sql语句

CREATE DATABASE ConfessionWall;
USE ConfessionWall;
-- 用户表
CREATE TABLE IF NOT EXISTS userTbl(
userId INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
userName VARCHAR(200) NOT NULL,
userAvatarId VARCHAR(500) NOT NULL,
userNickName VARCHAR(200),
userPassword VARCHAR(200) NOT NULL,
userQuestion VARCHAR(200),
userAge INT,
userSex VARCHAR(20),
userMajor VARCHAR(100),
userClass VARCHAR(100)
);

新建普通maven项目
新建maven项目删除结构,新建子项目;
在父项目的pom.xml中导入依赖

    <!--父工程-->
    <!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <!--mybatis-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--junit-->
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2-2.创建一个模块

  • 编写mybatis核心配置文件

在resources下新建文件mybatis-config.xml
注意在xml中的&符号需要转义&

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
    <!--环境(可以配置多个环境)-->
    <environments default="development">
        <environment id="development">
            <!--事务管理-->
            <transactionManager type="JDBC"/>
            <!--数据源-->
            <dataSource type="POOLED">
                <!--driver-->
                <property name="driver" value="${driver}"/>
                <!--url-->
                <property name="url" value="${url}"/>
                <!--数据库名-->
                <property name="username" value="${username}"/>
                <!--数据库密码-->
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--配置映射mapper.xml-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>
  • 编写mybatis工具类

com.baize.utils.MybatisUtil.java

/**
 * SqlSessionFactory--sqlSession
 */
public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    /*
    static方法会在类中自动运行
     */
    static {
        try {
            //使用mybatis 第一步:获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    // 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
    }
}

2-3.编写代码

  • 实体类
/**
 * 实体类
 */
public class User {
    private int id;
    private String name;
    private String sex;
    private String tell;
    private String addr;
    private int money;

    public User(int id, String name, String sex, String tell, String addr, int money) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.tell = tell;
        this.addr = addr;
        this.money = money;
    }

    public User() {}

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getTell() {
        return tell;
    }

    public void setTell(String tell) {
        this.tell = tell;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", tell='" + tell + '\'' +
                ", addr='" + addr + '\'' +
                ", money=" + money +
                '}';
    }
}
  • Dao接口

/**
 * 等价与之后的mapper
 */
public interface UserDao {
    List<User> getUserList();
}
  • 接口实现类
    没有mybatis之前
/**
 * 没有mybatis时的写法
 */
public class UserDaoImpl implements UserDao{
    @Override
    public List<User> getUserList() {
        //执行sql
        String sql = "";
        //返回结果集
        //******
        return null;
    }
}

有了mybatis之后

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace绑定一个对应的dao/mapper接口-->
<mapper namespace="com.baize.dao.UserDao">
    <!--
        查询语句
        id 对应查询名字
        resultType返回值类型
    -->
    <select id="getUserList" resultType="com.baize.entity.User">SELECT * FROM customer_table</select>
</mapper>

2-4.测试

在绿色文件夹中相同位置编写测试类(需要有junit)

/**
 * 测试类
 */
public class UserDaoTest {

    @Test
    public void test(){
        //获得SqlSession对象
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        //执行sql(方式一:getmapper)
//        UserDao userMapper = sqlSession.getMapper(UserDao.class);
//        List<User> userList = userMapper.getUserList();
        //方式2:(不推荐使用)
        List<User> users = sqlSession.selectList("com.baize.dao.UserDao.getUserList");

        for (User user:users) {
            System.out.print(user.getName());
        }
        //关闭sqlSession
        sqlSession.close();
    }
}

3.CRUD(增删改查)

UserDao(UserMapper.java)

/**
 * 等价与之后的mapper
 */
public interface UserDao {
    //获取全部用户
    List<User> getUserList();
    //根据id查询用户
    User getUserById(int id);
    //增加一个用户
    int addUser(User user);
    //修改一个用户
    int updateUser(User user);
    //删除一个用户
    int deleteUser(int id);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace绑定一个对应的dao/mapper接口-->
<mapper namespace="com.baize.dao.UserDao">
    <!--
        查询语句
        id 对应查询名字
        resultType返回值类型
    -->
    <select id="getUserList" resultType="com.baize.entity.User">
        SELECT * FROM customer_table
    </select>
    <select id="getUserById" resultType="com.baize.entity.User" parameterType="int">
        SELECT * FROM customer_table WHERE id = #{id}
    </select>
    <!--对象中的属性可以直接取出来-->
    <insert id="addUser" parameterType="com.baize.entity.User">
        INSERT INTO customer_table (id, name, sex, tell, addr, money) values(#{id},#{name},#{sex},#{tell},#{addr},#{money})
    </insert>
    <update id="updateUser" parameterType="com.baize.entity.User">
        UPDATE customer_table SET money=#{money},addr = #{addr} where id = #{id}
    </update>
    <delete id="deleteUser" parameterType="int">
        DELETE FROM customer_table where id = #{id}
    </delete>
</mapper>

UserDaoTest

package com.baize.dao;

import com.baize.entity.User;
import com.baize.utils.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

/**
 * 测试类
 */
public class UserDaoTest {

    @Test
    public void test(){
        //获得SqlSession对象
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        //执行sql(方式一:getmapper)
//        UserDao userMapper = sqlSession.getMapper(UserDao.class);
//        List<User> userList = userMapper.getUserList();
        //方式2:
        List<User> users = sqlSession.selectList("com.baize.dao.UserDao.getUserList");

        for (User user:users) {
            System.out.print(user.getName());
        }
        //关闭sqlSession
        sqlSession.close();
    }

    /**
     * 根据id查询用户
     */
    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = userDao.getUserById(1);
        System.out.println(user.toString());
        sqlSession.close();
    }
    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = new User(229,"张三","NAN","18271837181","BeiJing",2000);
        int result = userDao.addUser(user);
        //增删改需要 提交事务
        sqlSession.commit();
        System.out.println(result);
        sqlSession.close();
    }
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = new User();
        user.setId(1);
        user.setAddr("shanghai");
        user.setMoney(3000);
        int result = userDao.updateUser(user);
        System.out.println(result);
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        int result = userDao.deleteUser(1);
        System.out.println(result);
        sqlSession.commit();
        sqlSession.close();
    }
}

4.使用注解开发

4-1.mybatis 的常用注解说明

@Insert:实现新增 
@Update:实现更新 
@Delete:实现删除 
@Select:实现查询 
@Result:实现结果集封装 
@Results:可以与@Result 一起使用,封装多个结果集 
@ResultMap:实现引用@Results 定义的封装 
@One:实现一对一结果集封装 
@Many:实现一对多结果集封装 
@SelectProvider: 实现动态 SQL 映射 
@CacheNamespace:实现注解二级缓存的使用 

这里以查询为例:(因为其他的和之前的映射的写法相同)
UserMapper.java

public interface UserMapper {
    @Select("SELECT * FROM customer_table")
    List<User> userList();
}

MybatisUtil.java

/**
 * SqlSessionFactory--sqlSession
 */
public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    /*
    static方法会在类中自动运行
     */
    static {
        try {
            //使用mybatis 第一步:获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    // 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
    }
}

mybatis-config.xml
在这里,我们使用引入外部文件的方式引入数据库配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
    <!-- 引入外部配置文件-->
    <properties resource="jdbcConfig.properties"/>
    <!--配置别名-->
<!--    <typeAliases>-->
<!--        <package name="com.baize"></package>-->
<!--    </typeAliases>-->
    <!--环境(可以配置多个环境)-->
    <environments default="development">
        <environment id="development">
            <!--事务管理-->
            <transactionManager type="JDBC"/>
            <!--数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--配置UserMapper-->
    <mappers>
        <mapper class="com.baize.dao.UserMapper"/>
    </mappers>
</configuration>

jdbcConfig.properties

username=root
url=jdbc:mysql://localhost:3306/customer_db?serverTimezone=GMT&useSSL=true&useUnicode=true&characterEncoding=UTF-8
driver=com.mysql.cj.jdbc.Driver
password=12345678

dao层不再举例,和之前相同
以上就是使用注解开发的方式,当然在工作过程中这种方法只适用于简单的sql

5.log4j

Log4j是一种非常流行的日志框架,最新版本是2.x。
特点:

  • 控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;
  • 控制每一条日志的输出格式;
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
  • 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
  1. 导入log4j的包
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
  1. log4j.properties
log4j.rootLogger=DEBUG,console,dailyFile,im
log4j.additivity.org.apache=true
# 控制台(console)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.ImmediateFlush=true
log4j.appender.console.Target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 日志文件(logFile)
log4j.appender.logFile=org.apache.log4j.FileAppender
log4j.appender.logFile.Threshold=DEBUG
log4j.appender.logFile.ImmediateFlush=true
log4j.appender.logFile.Append=true
log4j.appender.logFile.File=D:/logs/log.log4j
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 回滚文件(rollingFile)
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.Threshold=DEBUG
log4j.appender.rollingFile.ImmediateFlush=true
log4j.appender.rollingFile.Append=true
log4j.appender.rollingFile.File=D:/logs/log.log4j
log4j.appender.rollingFile.MaxFileSize=200KB
log4j.appender.rollingFile.MaxBackupIndex=50
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 定期回滚日志文件(dailyFile)
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.Threshold=DEBUG
log4j.appender.dailyFile.ImmediateFlush=true
log4j.appender.dailyFile.Append=true
log4j.appender.dailyFile.File=D:/logs/log.log4j
log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 应用于socket
log4j.appender.socket=org.apache.log4j.RollingFileAppender
log4j.appender.socket.RemoteHost=localhost
log4j.appender.socket.Port=5001
log4j.appender.socket.LocationInfo=true
# Set up for Log Factor 5
log4j.appender.socket.layout=org.apache.log4j.PatternLayout
log4j.appender.socket.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
# 发送日志到指定邮件
log4j.appender.mail=org.apache.log4j.net.SMTPAppender
log4j.appender.mail.Threshold=FATAL
log4j.appender.mail.BufferSize=10
log4j.appender.mail.From = xxx@mail.com
log4j.appender.mail.SMTPHost=mail.com
log4j.appender.mail.Subject=Log4J Message
log4j.appender.mail.To= xxx@mail.com
log4j.appender.mail.layout=org.apache.log4j.PatternLayout
log4j.appender.mail.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 应用于数据库
log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.database.URL=jdbc:mysql://localhost:3306/test
log4j.appender.database.driver=com.mysql.jdbc.Driver
log4j.appender.database.user=root
log4j.appender.database.password=
log4j.appender.database.sql=INSERT INTO LOG4J (Message) VALUES('=[%-5p] %d(%r) --> [%t] %l: %m %x %n')
log4j.appender.database.layout=org.apache.log4j.PatternLayout
log4j.appender.database.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

# 自定义Appender
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@cybercorlin.net
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

3.配置log4j为日志的实现

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties resource="jdbcConfig.properties"/>
    <settings>
        <!--标准的日志工厂的实现-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--配置UserMapper-->
    <mappers>
        <mapper class=""/>
    </mappers>
</configuration>
  1. 简单使用
    1. 在要使用log4j的类中导入包
    2. 日志对象为当前类的Class
    static Logger logger = Logger.getLogger(Test.class);
    
    1. log4jTest
    import org.apache.log4j.Logger;
    
    public class Test {
        //
        static Logger logger = Logger.getLogger(Test.class);
        @org.junit.Test
        public void TestLog4j(){
            logger.info("info:进入了log4j");
            logger.debug("debug:进入了log4j");
            logger.error("error:进入了log4j");
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

师兄白泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值