Mybatis与Ehcache整合

Mybatis与Ehcache整合可以提高性能,降低数据库压力。查询百度发现整合Mybatis与Ehcache其实非常简单的。

1.

下载mybatis相关包与ehcache相关包

下载地址为:https://github.com/mybatis/ehcache-cache/releases

作者下载的是

mybatis-ehcache-1.0.3版本


其中自带了

mybatis-ehcache-1.0.3.jar

ehcache-core-2.6.8.jar

slf4j-api-1.6.1.jar


将这三个包导入到项目的jar文件下,就可以使用ehcache功能了。当然前提是保证mybatis没有引入ehcache前,项目也能正常运行。

作者用的mybatis3.2版本,框架用了SpringMVC3.2等等。


现在就试试效果吧。

在Map文件中打开echached效果,account-mapper.xml文件内容如下,(有的文章说还需要配置ehcache.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">
<mapper namespace="com.springdemo.mapper.AccountMapper">

    <!--mybatis ehcache缓存配置 -->
    <!-- 以下两个<cache>标签二选一,第一个可以输出日志,第二个不输出日志 -->
     <cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
     <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>


    <!-- 以下与实体类的中字段一致 -->
    <sql id="selectId">
        id,
        accountName,
        (select group_concat(name) from ly_role
        where ly_role.id
        in (SELECT role_id FROM acc_role WHERE
        acc_id=account.id) ) roleName,
        password,
        description,
        state,
        createTime
    </sql>

    <!--resultType="Account" 每返回一条结果封装到Account里 -->
    <select id="queryAll" resultType="Account" parameterType="Account">
        select
        <include refid="selectId" />
        from account
        <where>
            <if test="accountName != null and accountName != ''">
                accountName like '%${accountName}%'
            </if>
        </where>
    </select>

    <select id="isExist" resultType="Account" parameterType="String">
        select
        <include refid="selectId" />
        from account
        where accountName = #{accountName}
    </select>

    <!--resultType="Account" 每返回一条结果封装到Account里 -->
    <select id="query" resultType="Account" parameterType="java.util.HashMap">
        select
        <include refid="selectId" />
        from account
        <where>
            <if test="t.accountName != null and t.accountName != ''">
                accountName like '%${t.accountName}%'
            </if>
        </where>
        <if test="paging.startPage != null ">
        limit #{paging.startPage} , #{paging.pageSize}  
        </if>
    </select>
    <!--resultType="Account" 记录条数,用于翻页查询 -->
    <select id="queryCount" resultType="long"  parameterType="java.util.HashMap">
                select        count(*)
        from account
        <where>
            <if test="t.accountName != null and t.accountName != ''">
                accountName like '%${t.accountName}%'
            </if>
        </where>
    </select>
    
    <select id="queryNoMatch" resultType="Account" parameterType="java.util.HashMap">
        select
        a.id,
        a.accountName,
        a.password,
        a.accountType,
        a.description,
        a.state,
        a.createTime,
        (SELECT dp.name from department dp where dp.id =
        d.subdep_id) depName
        from account a LEFT JOIN dep_account d on
        a.id=d.account_id
        <where>
            <if test="t.accountName != null and t.accountName != ''">
                accountName like '%${t.accountName}%'
            </if>
        </where>
    </select>

    <!-- 增加用户 -->
    <insert id="add" parameterType="Account">
        insert into account (
        accountName,
        password,
        description,
        state )
        values (#{accountName},
        #{password}, #{description},
        #{state})
    </insert>

    <delete id="delete" parameterType="String">
        delete from account where
        id=#{id}
    </delete>

    <select id="getById" parameterType="String" resultType="Account">
        select
        <include refid="selectId" />
        from account where id=#{id}
    </select>

    <update id="update" parameterType="Account">
        update account
        <set>
            <if test="accountName != null and accountName != ''">
                accountName=#{accountName},
            </if>
            <if test="password != null and password != ''">
                password=#{password},
            </if>
            <if test="description != null and description != ''">
                description=#{description},
            </if>
            <if test="state != null and state != ''">
                state=#{state},
            </if>
            <if test="createTime != null and createTime != ''">
                createTime=#{createTime}
            </if>
        </set>
        where id=#{id}
    </update>

    <!-- 验证用户登陆 -->
    <select id="countAccount" parameterType="Account" resultType="Account">
        select
        <include refid="selectId" />
        from account where
        accountName=#{accountName} and password=#{password}
    </select>

    <!-- 根据用户名查出id -->
    <select id="querySingleAccount" parameterType="String"
        resultType="Account">
        select
        <include refid="selectId" />
        from account where accountName=#{accountName}
    </select>
</mapper>


然后运行Account的查询程序,未启用cache的日志如下:

DEBUG 2014-10-11 14:07:16,712 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-1 DispatcherServlet with name 'spring3' processing GET request for [/AnnExp2/background/account/list.do]
DEBUG 2014-10-11 14:07:16,712 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-1 Looking up handler method for path /background/account/list.do
DEBUG 2014-10-11 14:07:16,722 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-1 Returning handler method [public java.lang.String com.springdemo.usermgr.controller.AccountController.list(org.springframework.ui.Model,com.springdemo.usermgr.vo.Resources,java.lang.String)]
DEBUG 2014-10-11 14:07:16,722 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-1 Returning cached instance of singleton bean 'accountController'
DEBUG 2014-10-11 14:07:16,722 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-1 Last-Modified value for [/AnnExp2/background/account/list.do] is: -1
3
DEBUG 2014-10-11 14:07:16,742 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-1 Invoking afterPropertiesSet() on bean with name 'background/account/list'
DEBUG 2014-10-11 14:07:16,742 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-1 Rendering view [org.springframework.web.servlet.view.JstlView: name 'background/account/list'; URL [/WEB-INF/view/background/account/list.jsp]] in DispatcherServlet with name 'spring3'
DEBUG 2014-10-11 14:07:16,742 org.springframework.web.servlet.view.JstlView.http-bio-8080-exec-1 Added model object 'resources' of type [com.springdemo.usermgr.vo.Resources] to request in view with name 'background/account/list'
DEBUG 2014-10-11 14:07:16,742 org.springframework.web.servlet.view.JstlView.http-bio-8080-exec-1 Added model object 'org.springframework.validation.BindingResult.resources' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'background/account/list'
DEBUG 2014-10-11 14:07:16,742 org.springframework.web.servlet.view.JstlView.http-bio-8080-exec-1 Forwarding to resource [/WEB-INF/view/background/account/list.jsp] in InternalResourceView 'background/account/list'
2
DEBUG 2014-10-11 14:07:16,762 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-1 Successfully completed request
DEBUG 2014-10-11 14:07:16,762 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-1 Returning cached instance of singleton bean 'sqlSessionFactory'
DEBUG 2014-10-11 14:07:16,995 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-1 DispatcherServlet with name 'spring3' processing POST request for [/AnnExp2/background/account/query.do]
DEBUG 2014-10-11 14:07:16,995 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-1 Looking up handler method for path /background/account/query.do
DEBUG 2014-10-11 14:07:17,005 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-1 Returning handler method [public com.lanyuan.pulgin.mybatis.plugin.PageView com.springdemo.usermgr.controller.AccountController.query(com.springdemo.usermgr.vo.Account,java.lang.String,java.lang.String)]
DEBUG 2014-10-11 14:07:17,005 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-1 Returning cached instance of singleton bean 'accountController'
DEBUG 2014-10-11 14:07:17,005 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-1 Creating a new SqlSession
DEBUG 2014-10-11 14:07:17,005 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-1 SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1a891095] was not registered for synchronization because synchronization is not active
DEBUG 2014-10-11 14:07:17,049 com.springdemo.mapper.AccountMapper.http-bio-8080-exec-1 Cache Hit Ratio [com.springdemo.mapper.AccountMapper]: 0.0
DEBUG 2014-10-11 14:07:17,050 org.springframework.jdbc.datasource.DataSourceUtils.http-bio-8080-exec-1 Fetching JDBC Connection from DataSource
DEBUG 2014-10-11 14:07:17,051 org.mybatis.spring.transaction.SpringManagedTransaction.http-bio-8080-exec-1 JDBC Connection [jdbc:mysql://localhost:3306/test, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG 2014-10-11 14:07:17,051 com.springdemo.mapper.AccountMapper.queryCount.http-bio-8080-exec-1 ==>  Preparing: select count(*) from account
DEBUG 2014-10-11 14:07:17,051 com.springdemo.mapper.AccountMapper.queryCount.http-bio-8080-exec-1 ==> Parameters:
DEBUG 2014-10-11 14:07:17,052 com.springdemo.mapper.AccountMapper.queryCount.http-bio-8080-exec-1 <==      Total: 1

DEBUG 2014-10-11 14:07:17,053 net.sf.ehcache.store.disk.Segment.http-bio-8080-exec-1 put added 0 on heap
DEBUG 2014-10-11 14:07:17,053 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1a891095]
DEBUG 2014-10-11 14:07:17,053 org.springframework.jdbc.datasource.DataSourceUtils.http-bio-8080-exec-1 Returning JDBC Connection to DataSource
DEBUG 2014-10-11 14:07:17,053 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-1 Creating a new SqlSession
DEBUG 2014-10-11 14:07:17,054 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-1 SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@271ffe2f] was not registered for synchronization because synchronization is not active
DEBUG 2014-10-11 14:07:17,058 com.springdemo.mapper.AccountMapper.http-bio-8080-exec-1 Cache Hit Ratio [com.springdemo.mapper.AccountMapper]: 0.0
DEBUG 2014-10-11 14:07:17,058 org.springframework.jdbc.datasource.DataSourceUtils.http-bio-8080-exec-1 Fetching JDBC Connection from DataSource
DEBUG 2014-10-11 14:07:17,059 org.mybatis.spring.transaction.SpringManagedTransaction.http-bio-8080-exec-1 JDBC Connection [jdbc:mysql://localhost:3306/test, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG 2014-10-11 14:07:17,060 com.springdemo.mapper.AccountMapper.query.http-bio-8080-exec-1 ==>  Preparing: select id, accountName, (select group_concat(name) from ly_role where ly_role.id in (SELECT role_id FROM acc_role WHERE acc_id=account.id) ) roleName, password, description, state, createTime from account limit ? , ?
DEBUG 2014-10-11 14:07:17,060 com.springdemo.mapper.AccountMapper.query.http-bio-8080-exec-1 ==> Parameters: 0(Integer), 5(Integer)
DEBUG 2014-10-11 14:07:17,066 com.springdemo.mapper.AccountMapper.query.http-bio-8080-exec-1 <==      Total: 5

DEBUG 2014-10-11 14:07:17,066 net.sf.ehcache.store.disk.Segment.http-bio-8080-exec-1 put added 0 on heap
DEBUG 2014-10-11 14:07:17,067 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@271ffe2f]
DEBUG 2014-10-11 14:07:17,067 org.springframework.jdbc.datasource.DataSourceUtils.http-bio-8080-exec-1 Returning JDBC Connection to DataSource
DEBUG 2014-10-11 14:07:17,078 org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.http-bio-8080-exec-1 Written [com.lanyuan.pulgin.mybatis.plugin.PageView@380b2e5d] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@1da6205a]
3
DEBUG 2014-10-11 14:07:17,078 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-1 Null ModelAndView returned to DispatcherServlet with name 'spring3': assuming HandlerAdapter completed request handling
2
DEBUG 2014-10-11 14:07:17,078 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-1 Successfully completed request
DEBUG 2014-10-11 14:07:17,078 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-1 Returning cached instance of singleton bean 'sqlSessionFactory'
DEBUG 2014-10-11 14:07:17,099 net.sf.ehcache.store.disk.Segment.com%002espringdemo%002emapper%002e%0041ccount%004dapper.data fault removed 0 from heap
DEBUG 2014-10-11 14:07:17,099 net.sf.ehcache.store.disk.Segment.com%002espringdemo%002emapper%002e%0041ccount%004dapper.data fault added 0 on disk
DEBUG 2014-10-11 14:07:17,100 net.sf.ehcache.store.disk.Segment.com%002espringdemo%002emapper%002e%0041ccount%004dapper.data fault removed 0 from heap
DEBUG 2014-10-11 14:07:17,101 net.sf.ehcache.store.disk.Segment.com%002espringdemo%002emapper%002e%0041ccount%004dapper.data fault added 0 on disk

启用cache的命中后日志如下:

DEBUG 2014-10-11 14:07:52,907 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-5 DispatcherServlet with name 'spring3' processing GET request for [/AnnExp2/background/account/list.do]
DEBUG 2014-10-11 14:07:52,907 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-5 Looking up handler method for path /background/account/list.do
DEBUG 2014-10-11 14:07:52,917 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-5 Returning handler method [public java.lang.String com.springdemo.usermgr.controller.AccountController.list(org.springframework.ui.Model,com.springdemo.usermgr.vo.Resources,java.lang.String)]
DEBUG 2014-10-11 14:07:52,917 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-5 Returning cached instance of singleton bean 'accountController'
DEBUG 2014-10-11 14:07:52,917 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-5 Last-Modified value for [/AnnExp2/background/account/list.do] is: -1
3
DEBUG 2014-10-11 14:07:52,917 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-5 Rendering view [org.springframework.web.servlet.view.JstlView: name 'background/account/list'; URL [/WEB-INF/view/background/account/list.jsp]] in DispatcherServlet with name 'spring3'
DEBUG 2014-10-11 14:07:52,917 org.springframework.web.servlet.view.JstlView.http-bio-8080-exec-5 Added model object 'resources' of type [com.springdemo.usermgr.vo.Resources] to request in view with name 'background/account/list'
DEBUG 2014-10-11 14:07:52,917 org.springframework.web.servlet.view.JstlView.http-bio-8080-exec-5 Added model object 'org.springframework.validation.BindingResult.resources' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'background/account/list'
DEBUG 2014-10-11 14:07:52,917 org.springframework.web.servlet.view.JstlView.http-bio-8080-exec-5 Forwarding to resource [/WEB-INF/view/background/account/list.jsp] in InternalResourceView 'background/account/list'
2
DEBUG 2014-10-11 14:07:52,917 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-5 Successfully completed request
DEBUG 2014-10-11 14:07:52,917 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-5 Returning cached instance of singleton bean 'sqlSessionFactory'
DEBUG 2014-10-11 14:07:53,121 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-5 DispatcherServlet with name 'spring3' processing POST request for [/AnnExp2/background/account/query.do]
DEBUG 2014-10-11 14:07:53,121 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-5 Looking up handler method for path /background/account/query.do
DEBUG 2014-10-11 14:07:53,131 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.http-bio-8080-exec-5 Returning handler method [public com.lanyuan.pulgin.mybatis.plugin.PageView com.springdemo.usermgr.controller.AccountController.query(com.springdemo.usermgr.vo.Account,java.lang.String,java.lang.String)]
DEBUG 2014-10-11 14:07:53,131 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-5 Returning cached instance of singleton bean 'accountController'
DEBUG 2014-10-11 14:07:53,131 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-5 Creating a new SqlSession
DEBUG 2014-10-11 14:07:53,131 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-5 SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@61b38786] was not registered for synchronization because synchronization is not active
DEBUG 2014-10-11 14:07:53,131 com.springdemo.mapper.AccountMapper.http-bio-8080-exec-5 Cache Hit Ratio [com.springdemo.mapper.AccountMapper]: 0.25
DEBUG 2014-10-11 14:07:53,131 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-5 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@61b38786]
DEBUG 2014-10-11 14:07:53,131 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-5 Creating a new SqlSession
DEBUG 2014-10-11 14:07:53,131 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-5 SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d94e73a] was not registered for synchronization because synchronization is not active
DEBUG 2014-10-11 14:07:53,131 com.springdemo.mapper.AccountMapper.http-bio-8080-exec-5 Cache Hit Ratio [com.springdemo.mapper.AccountMapper]: 0.4
DEBUG 2014-10-11 14:07:53,131 org.mybatis.spring.SqlSessionUtils.http-bio-8080-exec-5 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d94e73a]
DEBUG 2014-10-11 14:07:53,131 org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.http-bio-8080-exec-5 Written [com.lanyuan.pulgin.mybatis.plugin.PageView@4c5c0e8b] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@1da6205a]
3
DEBUG 2014-10-11 14:07:53,131 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-5 Null ModelAndView returned to DispatcherServlet with name 'spring3': assuming HandlerAdapter completed request handling
2
DEBUG 2014-10-11 14:07:53,131 org.springframework.web.servlet.DispatcherServlet.http-bio-8080-exec-5 Successfully completed request
DEBUG 2014-10-11 14:07:53,131 org.springframework.beans.factory.support.DefaultListableBeanFactory.http-bio-8080-exec-5 Returning cached instance of singleton bean 'sqlSessionFactory'

可以看到前后明显差异,命中cache后,查询效率要明显提高。


  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
本工程用于研究如何借助Ehcache缓存框架实现对页面的缓存 本工程编码方式:UTF-8 本工程开发工具:MyEclipse 说明: 1、ehcache.xml和ehcache.xsd两个文件可以在下在下载下来的名为“ehcache-core-x.x.x-distribution.tar.gz”压缩文件中找到 2、由于要实现Ehcache缓存页面,所以必须要添加“ehcache-web-2.0.4.jar” jar包,该jar包主要用于辅助Ehcache实现页面缓存 注意: 本web工程的发布不要使用Tomcat7,否则会出现如下异常: 2015-3-25 9:53:50 org.apache.catalina.loader.WebappClassLoader loadClass 信息: Illegal access: this web application instance has been stopped already. Could not load net.sf.ehcache.store.disk.DiskStore$KeySet. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. java.lang.IllegalStateException at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1600) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559) at net.sf.ehcache.store.disk.DiskStore.keySet(DiskStore.java:560) at net.sf.ehcache.store.disk.DiskStorageFactory$DiskExpiryTask.run(DiskStorageFactory.java:838) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:181) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:205) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) 相关jar包下载地址: Ehcache 对象、数据缓存:http://ehcache.org/downloads/destination?name=ehcache-core-2.5.2-distribution.tar.gz&bucket=tcdistributions&file=ehcache
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值