Mybatis复习整理

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">

<mapper namespace="mapper.BlogMapper">
	
	<!--单独的cache作用: 
		所有的映射文件里的select都会被缓存
		所有的映射文件里的insert、update和delete语句执行都会被清空缓存
		缓存使用最近最少使用算法LRU来回收
		缓存不会被设定的时间所清空
		每个缓存可以存储1024个列表或对象的引用(不管查询方法返回的是什么)
		缓存将作为“读/写”缓存,意味着检索的对象不是共享里的且可以被调用者安全的修改,而不会被其他调用者或线程干扰
	 -->
	<cache/>
	<!-- eviction:缓存回收算法
			LRU:最近最少使用:移出最近最长事件内都没有被使用的对象
			FIFO:先进先出:移出最先进入缓存的对象
			SOFI:软引用:基于垃圾回收机制和软引用规则来移除对象(空间内存不足时才回收对象)
			WEAK:弱引用:基于垃圾回收机制和弱引用规则来移除对象(垃圾回收器扫描到才进行回收)
		 flushInterval:刷新时间间隔?
		 size:缓存对象的大小以及环境中的可用内存空间
		 readOnly:只读缓存将对所有调用者返回同一个实例。
		 	因此这些对象都不能被修改,这可以极大的提高性能。
		 	可写的缓存将通过序列化来返回一个缓存对象的拷贝。这会比较慢,但是比较安全。所以默认值都是false -->
	<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />
	<!-- 引用另外一个命名空间配置的缓存 -->
	<cache-ref namespace=""/>
	
	<!-- 使用自定义缓存==>如果想实现自定义缓存,必须实现org.mybatis.cache.Cache这个接口
		可以通过自己的缓存实现来完全重写缓存行为,或者通过创建第三方缓存解决方案的适配器 -->
	<cache type="something.MyBlogCache">
		<!-- 要配置自己的缓存,简单的添加一个公共的JavaBeans属性到缓存实现中,然后通过cache元素设置属性进行传递 -->
		<property name="cacheFile" value="/tmp/my-blog-cache.tmp"/>
	</cache>
	
	<!-- 描述如何从数据库结果集里面加载对象 -->
	<resultMap type="Blog" id="blog"></resultMap>
	<!-- 能够被其他语句重用的sql块 -->
	<sql id="columns"> 
		ID as id,
		AUTHOR as author,
		TITLE as title,
		CONTENT as content,
		CLICKTIMES as clicktimes 
	</sql>
	
	<!-- 根据主键查询 -->
	<select id="selectBlogById" parameterType="int" resultType="Blog">
		select <include refid="columns"/> from Blog where id = #{id}
	</select>
	
	<!--parameterType:参数类型
		resultType:返回值类型的具体类名
		resultMap:返回值类型的结果集
		flushCache:如果为true,每次该语句调用都会清空缓存 
		useCache:如果为true,则该语句的结果集将被缓存
		timeout:请求超时时间
		fetchSize:从数据库获得记录条数
		statementType:STATEMENT/~PREPARED/CALLABLE
		resultSetType:FORWARD_ONLY/SCROLL_SENSITIVE/SCROLL_INSENSITIVE -->
	<select id="exampleSelect" 
		parameterType="参数类型"  
		resultType="Blog"
		resultMap="Blog"
		flushCache="true"
		useCache="true"
		timeout="1000"
		fetchSize="256"
		statementType="STATEMENT"
		resultSetType="FORWARD_ONLY"></select>
		
	<!-- useGeneratedKeys : 数据库自动生成主键
		 keyProperty : 主键字段 -->
	<insert id="exampleInsert" useGeneratedKeys="true" keyProperty="id"></insert>
	
	<insert id="add" parameterType="Blog">
		insert into blog (id,author,title,content)
			values (#{id} , #{author} , #{title} , #{content} , #{clicktimes})
	</insert>
	
	<!-- 自定义数据类型转换,并指定转换类
		numericScale:指定小数位精度 -->
	<insert id="add2" parameterType="Blog">
		insert into blog (id,author,title,content)
			values (
			#{id , javaType=int , jdbcType=NUMERIC , typeHandler=ExampleTypeHandler } , 
			#{author} , 
			#{title} , 
			#{content},
			#{clicktimes,javaType=int,jdbcType=NUMERIC,numericScale=0})
	</insert>
	
	<!-- 这种申明结果集的方法可以解决列名不匹配的问题,和columns的效果相同 -->
	<resultMap type="Blog" id="blogs">
		<!-- 各属性解释
			property:映射数据库列的字段或属性(对应javaBean)
			column:数据库中的列名或者列标签的别名(对应数据库列)
			javaType:完整的java类名或者列标签名
			jdbcType:数据库中该列的字段类型(这个属性在insert、update或delete的时候针对允许空的列有用)
			typeHandler:数据类型处理器
		 -->
		<id column="ID" property="id" />
		<result column="AUTHOR" property="author"/>
		<result column="TITLE" property="title"/>
		<result column="CONTENT" property="content"/>
		<result column="CLICKTIMES" property="clicktimes"/>
	</resultMap>
	
	
	<!-- 一个多表关联的复合查询 -->
	<select id="selectBlogDetails" parameterType="int" resultMap="detailedBlogResultMap">
		select
			B.id as blog_id,
			B.title as blog_title,
			B.author_id as blog_author_id,
			A.id as author_id,
			A.username as author_username,
			A.password as author_password,
			A.email as author_email,
			A.bio as author_bio,
			A.favourite_section as author_favourite_section,
			P.id as post_id,
			P.blog_id as post_blog_id,
			P.author_id as post_author_id,
			P.created_on as post_created_on,
			P.section as post_section,
			P.subject as post_subject,
			P.draft as draft,
			P.body as post_body,
			C.id as comment_id,
			C.post_id as comment_post_id,
			C.name as comment_name,
			C.comment as comment_text,
			T.id as tag_id,
			T.name as tag_name
		from Blog B
			left outer join Author A on B.author_id = A.id
			left outer join Post P on B.id = P.blog_id
			left outer join Comment C on P.id = C.post_id
			left outer join Post_Tag PT on PT.post_id = P.id
			left outer join Tag T on PT.tag_id = T.id
		where B.id = #{id}
	</select>
	
	<!-- 将上一步的多表关联查询映射到一个智能的对象模型中 -->
	<resultMap id="detailedBlogResultMap" type="Blog">
		<!-- 实例化的时候通过构造器将结果注入到类中 -->
		<constructor>
			<!-- idArg:将结果集标记为ID,以方便全局调用
					arg:注入构造器的结果集 
				使用构造器将主表数据注入类中 -->
			<idArg column="blog_id" javaType="int"/>
		</constructor>
		<!-- 注入一个字段或者javaBean属性的结果
			主表数据单独用result申明 -->
		<result property="title" column="blog_title"/>
		<!-- 复杂类型联合:许多查询结果合成这个类型
			使用blog_author_id外键关联author表中需要查询的字段 -->
		<association property="author" column="blog_author_id" javaType=" Author">
			<id property="id" column="author_id"/>
			<result property="username" column="author_username"/>
			<result property="password" column="author_password"/>
			<result property="email" column="author_email"/>
			<result property="bio" column="author_bio"/>
			<result property="favouriteSection" column="author_favourite_section"/>
		</association>
		<!-- 复杂类型集合
			使用post_id外键关联post表中需要的字段 -->
		<collection property="posts" ofType="Post">
			<!-- post.id -->
			<id property="id" column="post_id"/>
			<!-- post.subject -->
			<result property="subject" column="post_subject"/>
			<!-- post与author表关联的字段 -->
			<association property="author" column="post_author_id" javaType="Author"/>
			<!-- comment_id作为外键与post关联,所以申明在post的关联对象中 -->
			<collection property="comments" column="post_id" ofType=" Comment">
				<id property="id" column="comment_id"/>
			</collection>
			<!-- tag_id 作为外键与post关联 -->
			<collection property="tags" column="post_id" ofType=" Tag" >
				<id property="id" column="tag_id"/>
			</collection>
			<!-- 使用一个结果值,以确定使用哪个resultMap -->
			<discriminator javaType="int" column="draft">
				<!-- 基于不同的结果映射 -->
				<case value="1" resultType="DraftPost"/>
			</discriminator>
		</collection>
	</resultMap>
	
	<!-- 一对一关联配置 -->
	<!-- 使用association和select属性做嵌套查询
		使用这种配置方法会导致N+1选择问题的产生
			执行单条sql语句获得一个表的记录
			对获得的列表中的每条记录,在执行一次联合查询用以加载详细信息
		这样会导致成千上万条sql执行,并非可取 -->
	<resultMap type="Blog" id="blogResult">
		<association property="author" column="blog_author_id" 
			javaType="Author" select="selectAuthor" />
	</resultMap>
	<select id="selectBlog" resultMap="blogResult" parameterType="int">
		select * from blog where id = #{id}
	</select>
	<select id="selectAuthor" resultMap="author" parameterType="int">
		select * from author where id = #{id}
	</select>
	<!-- 以上的结果相当于sql:
		select b.*,a.* from blog b
			left join author a on b.blog_author_id = a.id
			where b.id = #{id}  -->
			
	<!-- 第二种映射结果集的方式 -->
	<select id="selectBlog" parameterType="int" resultMap="blogResult">
		select
			B.id 		as blog_id,
			B.title 	as blog_title,
			B.author_id as blog_author_id,
			A.id 		as author_id,
			A.username  as author_username,
			A.password  as author_password,
			A.email 	as author_email,
			A.bio 		as author_bio
		from Blog B 
			left outer join Author A on B.author_id = A.id
		where B.id = #{id}
	</select>
	<resultMap id="blogResult" type="Blog">
		<id property="id" column=" blog_id" />
		<result property="title" column="blog_title"/>
		<association property="author" column="blog_author_id" javaType="Author"
			resultMap="authorResult"/>
			<!-- lable209 -->
	</resultMap>
	<!-- 这样写便于查询结果集重用,如果只要用一次的话,直接将resultMap标签中的内容移动到lable209 -->
	<resultMap id="authorResult" type="Author">
		<id property="id" column="author_id"/>
		<result property="username" column="author_username"/>
		<result property="password" column="author_password"/>
		<result property="email" column="author_email"/>
		<result property="bio" column="author_bio"/>
	</resultMap>
	
	<!-- 一对多关联配置 -->
	<resultMap id="blogResult" type="Blog">
		<collection property="posts" javaType="ArrayList" column="blog_id"
			ofType="Post" select="selectPostsForBlog"/>
	</resultMap>
	<select id="selectBlog" parameterType="int" resultMap="blogResult">
		SELECT * FROM BLOG WHERE ID = #{id}
	</select>
	<select id="selectPostsForBlog" parameterType="int" resultType="Author">
		SELECT * FROM POST WHERE BLOG_ID = #{id}
	</select>
	
	<!-- Discriminator:识别器~switch -->
	<resultMap id="vehicleResult" type="Vehicle">
		<id property="id" column="id" />
		<result property="vin" column="vin"/>
		<result property="year" column="year"/>
		<result property="make" column="make"/>
		<result property="model" column="model"/>
		<result property="color" column="color"/>
		<discriminator javaType="int" column="vehicle_type">
			<!-- 每当匹配中一个case,其余case将被忽略 -->
			<case value="1" resultMap="carResult"/>
			<case value="2" resultMap="truckResult"/>
			<case value="3" resultMap="vanResult"/>
			<case value="4" resultMap="suvResult"/>
		</discriminator>
	</resultMap>
	
	<!-- 动态sql -->
	<!-- if -->
	<select id="findBlogTitleLike" parameterType="Blog">
		select * from blog where 1=1 
		<if test="title != null">
			and title like #{title}
		</if>
	</select>
	
	<!-- choose -->
	<select id="findBlogLike" parameterType="Blog">
		select * from blog where 1=1 
		<choose>
			<when test="title != null">
				and title like #{title}
			</when>
			<when test="author != null and author.name != null">
				and title like #{author.name}
			</when>
			<otherwise>
				and featured = 1
			</otherwise>
		</choose>
	</select>
	
	<!-- where : 如果第一个条件不满足,但是第二个条件满足,则会忽略第二个条件的and -->
	<select id="findBlogWithWhere" parameterType="Blog">
		select * from blog
		<where>
			<if test="title != null">
				title like #{title}
			</if>
			<if test="author != null and author.name != null">
				and author like #{author.name}
			</if>
		</where>
	</select>
	
	<!-- trim==>where : 使用trim实现where同样的功能 -->
	<select id="findBlogWithTrim" parameterType="Blog">
		select * from blog 
		<trim prefix="where" prefixOverrides="and/or">
			<if test="title != null">
				title like #{title}
			</if>
			<if test="author != null and author.name != null">
				and author like #{author.name}
			</if>
		</trim>
	</select>
	
	<!-- set -->
	<update id="updateWithSet" parameterType="Blog">
		update blog
		<set>
			<if test="author != null">author = #{author},</if>
			<if test="content != null">content = #{content}</if>
		</set>
		where id = #{id}
	</update>
	
	<!-- trim==>set -->
	<update id="updateWithTrim" parameterType="Blog">
		update blog
		<trim prefix="set" prefixOverrides=",">
			<if test="author != null">author = #{author},</if>
			<if test="content != null">content = #{content}</if>
		</trim>
		where id = #{id}
	</update>
	
	<!-- foreach -->
	<!-- 注意:当传递一个集合给mybatis时,mybatis会自动将参数包装成map并且以名字作为key
			list==》list,array==》array -->
	<select id="selectBlogIn">
		select * from blog
		where id in
		<foreach collection="list" item="item" index="index" open="(" close=")" separator=",">
			#{item}
		</foreach>
	</select>
	
	
</mapper>
使用注解方式绑定sql

public interface BlogMapper {


	@Select("select * from Blog where id = #{id}")
	public Blog selectBlogById(int id);
	
	public void update(Blog blog);
	
}


自定义的类型处理器
/**
 * @author Administrator
 *	自己的数据类型处理器
 */
public class ExampleTypeHandler implements TypeHandler{
	
	@Override
	public Object getResult(ResultSet rs, String columnName) throws SQLException {
		return rs.getString(columnName);
	}


	@Override
	public Object getResult(CallableStatement cs, int columnIndex)
			throws SQLException {
		return cs.getString(columnIndex);
	}


	@Override
	public void setParameter(PreparedStatement ps, int i, Object parameter,
			JdbcType jdbcType) throws SQLException {
		ps.setString(i, (String) parameter);
	}


}


自定义插件
@Intercepts(
	{@Signature(type = Executor.class, method = "update",
			args = {BlogMapper.class,Object.class})}
		)
public class ExamplePlugin implements Interceptor{


	@Override
	public Object intercept(Invocation arg0) throws Throwable {
		return arg0.proceed();
	}


	@Override
	public Object plugin(Object arg0) {
		return Plugin.wrap(arg0, this);
	}


	@Override
	public void setProperties(Properties arg0) {
		
	}


}


自定义ObjectFactory
public class ExampleObjectFactory extends DefaultObjectFactory{


	@Override
	public Object create(Class type, List<Class> constructorArgTypes,
			List<Object> constructorArgs) {
		return super.create(type, constructorArgTypes, constructorArgs);
	}


	@Override
	public Object create(Class type) {
		return super.create(type);
	}


	/* 用来配置ExampleObjectFactory
	 * 在初始化ExampleObjectFactory实例后,定义在ExampleObjectFactory元素主体中的属性会以参数的形式传递到此方法中
	 * @see org.apache.ibatis.reflection.factory.DefaultObjectFactory#setProperties(java.util.Properties)
	 */
	@Override
	public void setProperties(Properties properties) {
		super.setProperties(properties);
	}
	
}


<?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="config/config.properties">
		<!-- 如果config.properties文件中有username和password属性,再次配置将会覆盖文件中的值 -->
		<property name="username" value="bikeeverywhere"/>
		<property name="password" value="bikeeverywhere"/>
	</properties>
	
	<!-- 设置和改变Mybatis运行中的行为 -->
	<settings>
		<!-- 全局性的启用或者禁用所有在mapper配置文件中配置的缓存 -->
		<setting name="cacheEnable" value="true"/>
		<!-- 全局性的启用或禁用延迟加载。当禁用时,所有关联的配置都会立即加载 -->
		<setting name="lazyLoadingEnable" value="true"/>
		<!-- 当启用时,一个有延迟加载属性的对象的任何一个延迟属性被加载时,该对象的所有的属性都会被加载。
			否则所有属性都是按需加载 -->
		<setting name="aggressiveLazyLoading" value="true"/>
		<!-- 允许或禁止从单一的语句返回多个结果集(需要驱动程序兼容) -->
		<setting name="multipleResultSetsEnable" value="true"/>
		<!-- 使用列的标签而不是列的名称 -->
		<setting name="userColumnLable" value="true"/>
		<!-- 允许JDBC自动生成主键(需要驱动程序兼容) -->
		<setting name="userGeneratedKeys" value="false"/>
		<!-- 指定mybatis是否以及如何自动将列映射到字段/属性
			partial:自动映射简单的、非嵌套的结果集
			full:自动映射任何复杂的(嵌套或非嵌套的结果集) -->
		<setting name="autoMappingBehavior" value="partial"/>
		<!-- 配置默认的执行器(executor)
			simple:简单的执行器
			reuse:重用prepared statements的执行器
			batch:重用statements并且进行批量更新的执行器 -->
		<setting name="defaultExecutorType" value="simple"/>
		<!-- 设置数据库查询超时时间 -->
		<setting name="defaultStatementTimeout" value="10000"/>
	</settings>
	
	<!-- 实体类设置别名 -->
	<typeAliases>
		<typeAlias type="entity.Author" alias="author"/>
		<typeAlias type="entity.Blog" alias="blog"/>
		<typeAlias type="entity.Comment" alias="comment"/>
		<typeAlias type="entity.Post" alias="post"/>
		<typeAlias type="entity.Section" alias="section"/>
		<typeAlias type="entity.Tag" alias="tag"/>
	</typeAliases>
	
	<!-- 数据库数据与java数据做类型转换使用 -->
	<typeHandlers>
		<!-- 可以重写类型处理器,或者建立自己的类型处理器去处理没有被支持的或非标准的类型
			要做到这一点,只要实现TypeHandler接口(org.mybatis.type),
			并且将TypeHandler类映射到java类型和可选的JDBC类型即可 -->
		<!-- 指定自己的数据类型转换,将VARCHAR转成String -->
		<typeHandler handler="handler.ExampleTypeHandler" javaType="String" jdbcType="VARCHAR"/>
	</typeHandlers>
	
	<!-- Mybatis每次创建一个结果对象都会使用objectFactory实例。
		使用默认的objectFactory和使用默认的构造函数来实例化目标类并没有什么区别 -->
	<objectFactory type="factory.ExampleObjectFactory">
		<property name="someProperty" value="100"/>
	</objectFactory>
	
	<!-- 自定义插件,在映射语句执行的某个时间点拦截方法调用 -->
	<plugins>
		<!-- 允许拦截的方法 -->
		<!-- Executor:
				query,update,flushStatements,commit,rollback,getTransaction,close,isClosed -->
		<!-- ParameterHandler:
				getParameterObject,setParameters -->
		<!-- ResultSetHandler:
				handlerResultSets,handlerOutputParameters -->
		<!-- StatementHandler:
				prepare,parameterize,batch,update,query -->
		<plugin interceptor="plugin.ExamplePlugin">
			<property name="someProperty" value="100"/>
		</plugin>
	</plugins>
	
	<!-- 配置运行环境 
			可能出现一个sql语句向两个数据库发起请求,所以要配置多个数据源
			但是:每个sqlsessionFactory只能选择一个运行环境
			所以如果连接多个数据库,就要配置多个sqlsessionFactory-->
	<environments default="development">
		<environment id="development">
			<!-- 事物管理:JDBC/MANAGED -->
			<!-- 	JDBC:直接使用JDBC的提交和回滚功能,它依赖于从数据源获得连接来管理事物的生命周期  -->
			<transactionManager type="JDBC" />
			<!-- 只有使用了延迟加载才需要数据源? -->
			<!-- Mybatis内置了3种数据源类型 -->
			<!--	UNPOOLED:每次需要的时候简单的打开和关闭连接
				 	虽然有点慢,但是对于不需要立即响应的简单的应用来说,不失为一种好的选择-->
			<dataSource type="UNPOOLED">
				<property name="driver" value="${driver}"/>
				<property name="url" value="${url}"/>
				<property name="username" value="${username}"/>
				<property name="password" value="${password}"/>
			</dataSource>
		</environment>
		<environment id="product">
			<!-- MANAGED:什么都不做,而是让容器来管理事务的生命周期
					如果需要通过关闭连接来停止事务,将属性closeConnection设置为false-->
			<transactionManager type="MANAGED" >
				<property name="closeConnection" value="false"/>
			</transactionManager>
			<!-- POOLED:这个数据源的实现缓存了JDBC连接对象(池化技术) -->
			<dataSource type="POOLED">
				<property name="driver" value="${driver1}"/>
				<property name="url" value="${url1}"/>
				<property name="username" value="${username1}"/>
				<property name="password" value="${password1}"/>
				<!-- 池化技术相关参数设定 -->
				<!-- 最大使用数量,默认为10 -->
				<property name="poolMaximumActiveConnections" value="10"/>
				<!-- 在特定时间内空闲的连接数(当没有人访问的时候也保持一定数量的连接) -->
				<property name="poolMaximumIdleConnections" value="5"/>
				<!-- 在连接池被强行返回前,一个连接能够“检出”的总时间,默认是20000ms -->
				<property name="poolMaximumCheckoutTime" value="20000"/>
				<!-- 这是一个比较底层的设置,如果连接占用了很长的时间,能够给连接池一个去打印日志的机会,并尝试重新连接,默认是20000ms -->
				<property name="poolTimeToWait" value="2000"/>
				<!-- ping query 是发送给数据库的ping信息,测试数据库是否良好和是否准备好了接受请求
						默认值是 NO PING QUERY SET,让大部分数据库都不适用ping,返回一个友好的错误信息 -->
				<property name="poolPingQuery" value=""/>
				<!-- ping query 的开关,如果允许,需要设置一条可用的(最高效的)sql语句来设置pingquery的值 -->
				<property name="poolPingEnable" value="false"/>
				<!-- 这个属性设置ping query的间隔时间。通常设置为数据库连接的超时时间,避免不必要的ping
						只有poolPingEnable=true时才生效 -->
				<property name="poolPingConnectionsNotUsedFor" value="0"/>
			</dataSource>
		</environment>
		<environment id="test">
			<transactionManager type="JDBC" />
			<dataSource type="JNDI">
				<property name="driver" value="${driver2}"/>
				<property name="url" value="${url2}"/>
				<property name="username" value="${username2}"/>
				<property name="password" value="${password2}"/>
				<!-- 这个属性用来从InitalContext中查找一个上下文 -->
				<property name="initial_context" value=""/>
				<!-- 这个属性是引用一个能够被找到的数据源实例的上下文路径
						它会查找根据 initial_context 从 initialContext 中搜寻返回的上下文。
						或者在initial_context 没有提供的情况下直接在 InitialContext 中进行查找。 -->
				<property name="data_source" value=""/>
			</dataSource>
		</environment>
	</environments>
	
	<!-- 此处用于配置sql映射 -->
	<mappers>
		<!-- 引入根目录下的配置文件 -->
		<mapper resource="mapper/BlogMapper.xml"/>
		<!-- 使用资源路径引入 -->
		<mapper url="file:///var/sqlmaps/AuthorMapper.xml"/>
	</mappers>
</configuration>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值