欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MyBatis Generator生成的$ sql是否存在注入风险详解

程序员文章站 2022-06-17 22:29:42
目录代理商sql注入问题排查准备测试demoentityproduct.javaproductexample.java控制层productcontroller.javaservice层products...

代理商sql注入问题排查

经全面排查,代理商中sql层使用'$'获取对象的只有一种类型,代码格式如下:

<sql id="example_where_clause">
   <!-- warning - @mbggenerated this element is automatically generated by 
      mybatis generator, do not modify. -->
  <where>
      <foreach collection="oredcriteria" item="criteria" separator="or">
         <if test="criteria.valid">
            <trim prefix="(" suffix=")" prefixoverrides="and">
               <foreach collection="criteria.criteria" item="criterion">
                  <choose>
                     <when test="criterion.novalue">
                        and ${criterion.condition}
                     </when>
                     <when test="criterion.singlevalue">
                        and ${criterion.condition} #{criterion.value}
                     </when>
                     <when test="criterion.betweenvalue">
                        and ${criterion.condition} #{criterion.value} and
                        #{criterion.secondvalue}
                     </when>
                     <when test="criterion.listvalue">
                        and ${criterion.condition}
                        <foreach collection="criterion.value" item="listitem"
  open="(" close=")" separator=",">
                           #{listitem}
                        </foreach>
                     </when>
                  </choose>
               </foreach>
            </trim>
         </if>
      </foreach>
   </where>
</sql>

接下来我们在测试demo中复现下情况:

准备测试demo

entity

product.java

普通实体类,对应数据库中product表,表结构见附录:

package com.zhrb.springcloud.entity;
import lombok.data;
import lombok.tostring;
/**
 * @classname product
 * @description todo
  * @author administrator
 * @date 2019/9/3 14:26
 * @version
  */ @data @tostring public class product {
    //主键
  private long pid;
    //产品名称
  private string productname;
    // 来自哪个数据库,因为微服务架构可以一个服务对应一个数据库,同一个信息被存储到不同数据库
  private string dbsource;
}

productexample.java

同代理商环境一样的动态条件类:

package com.zhrb.springcloud.entity;
import java.util.arraylist;
import java.util.list;
/**
 * @classname productexample
 * @description todo
  * @author administrator
 * @date 2019/9/20 9:07
 * @version
  */ public class productexample {
    /**
 * this field was generated by mybatis generator. * this field corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected string orderbyclause;
    /**
 * this field was generated by mybatis generator. * this field corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected boolean distinct;
    /**
 * this field was generated by mybatis generator. * this field corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected list<criteria> oredcriteria;
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public productexample() {
        oredcriteria = new arraylist<criteria>();
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void setorderbyclause(string orderbyclause) {
        this.orderbyclause = orderbyclause;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public string getorderbyclause() {
        return orderbyclause;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void setdistinct(boolean distinct) {
        this.distinct = distinct;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public boolean isdistinct() {
        return distinct;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public list<criteria> getoredcriteria() {
        return oredcriteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void or(criteria criteria) {
        oredcriteria.add(criteria);
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public criteria or() {
        criteria criteria = createcriteriainternal();
        oredcriteria.add(criteria);
        return criteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public criteria createcriteria() {
        criteria criteria = createcriteriainternal();
        if (oredcriteria.size() == 0) {
            oredcriteria.add(criteria);
        }
        return criteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected criteria createcriteriainternal() {
        criteria criteria = new criteria();
        return criteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void clear() {
        oredcriteria.clear();
        orderbyclause = null;
        distinct = false;
    }
    /**
 * this class was generated by mybatis generator. * this class corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected abstract static class generatedcriteria {
        protected list<criterion> criteria;
        protected generatedcriteria() {
            super();
            criteria = new arraylist<criterion>();
        }
        public boolean isvalid() {
            return criteria.size() > 0;
        }
        public list<criterion> getallcriteria() {
            return criteria;
        }
        public list<criterion> getcriteria() {
            return criteria;
        }
        protected void addcriterion(string condition) {
            if (condition == null) {
                throw new runtimeexception("value for condition cannot be null");
            }
            criteria.add(new criterion(condition));
        }
        protected void addcriterion(string condition, object value, string property) {
            if (value == null) {
                throw new runtimeexception("value for " + property + " cannot be null");
            }
            criteria.add(new criterion(condition, value));
        }
        protected void addcriterion(string condition, object value1, object value2, string property) {
            if (value1 == null || value2 == null) {
                throw new runtimeexception("between values for " + property + " cannot be null");
            }
            criteria.add(new criterion(condition, value1, value2));
        }
        public criteria andidisnull() {
            addcriterion("pid is null");
            return (criteria) this;
        }
        public criteria andidisnotnull() {
            addcriterion("pid is not null");
            return (criteria) this;
        }
        public criteria andidequalto(string value) {
            addcriterion("pid =", value, "pid");
            return (criteria) this;
        }
        public criteria andidnotequalto(string value) {
            addcriterion("pid <>", value, "pid");
            return (criteria) this;
        }
        public criteria andidgreaterthan(string value) {
            addcriterion("pid >", value, "pid");
            return (criteria) this;
        }
        public criteria andidgreaterthanorequalto(string value) {
            addcriterion("pid >=", value, "pid");
            return (criteria) this;
        }
        public criteria andidlessthan(string value) {
            addcriterion("pid <", value, "pid");
            return (criteria) this;
        }
        public criteria andidlessthanorequalto(string value) {
            addcriterion("pid <=", value, "pid");
            return (criteria) this;
        }
        public criteria andidlike(string value) {
            addcriterion("pid like", value, "pid");
            return (criteria) this;
        }
        public criteria andidnotlike(string value) {
            addcriterion("pid not like", value, "pid");
            return (criteria) this;
        }
        public criteria andidin(list<string> values) {
            addcriterion("pid in", values, "pid");
            return (criteria) this;
        }
        public criteria andidnotin(list<string> values) {
            addcriterion("pid not in", values, "pid");
            return (criteria) this;
        }
        public criteria andidbetween(string value1, string value2) {
            addcriterion("pid between", value1, value2, "pid");
            return (criteria) this;
        }
        public criteria andidnotbetween(string value1, string value2) {
            addcriterion("pid not between", value1, value2, "pid");
            return (criteria) this;
        }
    }
    /**
 * this class was generated by mybatis generator. * this class corresponds to the database table cpt_dls_config * * @mbggenerated do_not_delete_during_merge
 */  public static class criteria extends generatedcriteria {
        protected criteria() {
            super();
        }
    }
    /**
 * this class was generated by mybatis generator. * this class corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public static class criterion {
        private string condition;
        private object value;
        private object secondvalue;
        private boolean novalue;
        private boolean singlevalue;
        private boolean betweenvalue;
        private boolean listvalue;
        private string typehandler;
        public string getcondition() {
            return condition;
        }
        public object getvalue() {
            return value;
        }
        public object getsecondvalue() {
            return secondvalue;
        }
        public boolean isnovalue() {
            return novalue;
        }
        public boolean issinglevalue() {
            return singlevalue;
        }
        public boolean isbetweenvalue() {
            return betweenvalue;
        }
        public boolean islistvalue() {
            return listvalue;
        }
        public string gettypehandler() {
            return typehandler;
        }
        protected criterion(string condition) {
            super();
            this.condition = condition;
            this.typehandler = null;
            this.novalue = true;
        }
        protected criterion(string condition, object value, string typehandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.typehandler = typehandler;
            if (value instanceof list<?>) {
                this.listvalue = true;
            } else {
                this.singlevalue = true;
            }
        }
        protected criterion(string condition, object value) {
            this(condition, value, null);
        }
        protected criterion(string condition, object value, object secondvalue, string typehandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.secondvalue = secondvalue;
            this.typehandler = typehandler;
            this.betweenvalue = true;
        }
        protected criterion(string condition, object value, object secondvalue) {
            this(condition, value, secondvalue, null);
        }
    }
}

控制层productcontroller.java

package com.zhrb.springcloud.controller;
import com.zhrb.springcloud.entity.product;
import com.zhrb.springcloud.entity.productexample;
import com.zhrb.springcloud.service.productservice;
import io.swagger.annotations.api;
import io.swagger.annotations.apioperation;
import org.mybatis.spring.annotation.mapperscan;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.*;
import java.util.collection;
import java.util.list;
/**
 * @classname productcontroller
 * @description todo
  * @author zhrb
 * @date 2019/9/3 15:18
 * @version
  */ @restcontroller @requestmapping("/product")
@mapperscan("com.zhrb.springcloud.mapper")
@api(value = "/product",description = "商品管理 程序员小圈圈",position = 1)
public class productcontroller {
    @autowired
  private productservice productservice;
    
    @apioperation(value="测试是否预编译", notes="测试是否预编译")
    @getmapping(value = "/testlist")
    public list<product> testlist() {
        productexample example = new productexample();
        example.createcriteria().andidlike("1' or '1=1");
        list<product> productlist = productservice.list(example);
        for (product p :productlist){
            p.setproductname(p.getproductname()+"本条数据来自8001");
        }
        return productlist;
    }
}

service层

productservice.java

package com.zhrb.springcloud.service;
import com.zhrb.springcloud.entity.product;
import com.zhrb.springcloud.entity.productexample;
import java.util.list;
/**
 * @classname productservice
 * @description todo
  * @author administrator
 * @date 2019/9/3 15:15
 * @version
  */ public interface productservice {
    list<product> list(productexample example);
}

productserviceimpl.java

package com.zhrb.springcloud.service.impl;
import com.zhrb.springcloud.entity.product;
import com.zhrb.springcloud.entity.productexample;
import com.zhrb.springcloud.mapper.productmapper;
import com.zhrb.springcloud.service.productservice;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;
import java.util.list;
/**
 * @classname productserviceimpl
 * @description todo
  * @author administrator
 * @date 2019/9/3 15:16
 * @version
  */   @service public class productserviceimpl implements productservice{
    @autowired
  private productmapper productmapper;
    
    @override
  public list<product> list(productexample example) {
        return productmapper.testlist(example);
    }
}

mapper

productcontroller.java

package com.zhrb.springcloud.mapper;
import com.zhrb.springcloud.entity.product;
import com.zhrb.springcloud.entity.productexample;
import org.apache.ibatis.annotations.mapper;
import java.util.list;
/**
 * @classname productmapper
 * @description todo
  * @author administrator
 * @date 2019/9/3 14:55
 * @version
  */ 
  @mapper 
  public interface productmapper {
   
    list<product> testlist(productexample example);
}

productcontroller.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.zhrb.springcloud.mapper.productmapper">
    
    <select id="testlist" parametertype="com.zhrb.springcloud.entity.productexample" resulttype="com.zhrb.springcloud.entity.product">
        select
        pid, product_name, db_source
        from product
        <if test="_parameter != null" >
            <include refid="example_where_clause" />
        </if>
        <if test="orderbyclause != null" >
            order by ${orderbyclause}
        </if>
    </select>
    <sql id="example_where_clause" >
        <!--
 warning - @mbggenerated this element is automatically generated by mybatis generator, do not modify. -->  <where >
            <foreach collection="oredcriteria" item="criteria" separator="or" >
                <if test="criteria.valid" >
                    <trim prefix="(" suffix=")" prefixoverrides="and" >
                        <foreach collection="criteria.criteria" item="criterion" >
                            <choose >
                                <when test="criterion.novalue" >
                                    and ${criterion.condition}
                                </when>
                                <when test="criterion.singlevalue" >
                                    and ${criterion.condition} #{criterion.value}
                                </when>
                                <when test="criterion.betweenvalue" >
                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondvalue}
                                </when>
                                <when test="criterion.listvalue" >
                                    and ${criterion.condition}
                                    <foreach collection="criterion.value" item="listitem" open="(" close=")" separator="," >
                                        #{listitem}
                                    </foreach>
                                </when>
                            </choose>
                        </foreach>
                    </trim>
                </if>
            </foreach>
        </where>
    </sql>
</mapper>

测试

测试1:正常逻辑测试

首先按照正常代码逻辑测试,校验代码是否成功,测试结果截图如下:

MyBatis Generator生成的$ sql是否存在注入风险详解

可以看到调用成功,证明代码逻辑没问题,接下来进行异常测试:

测试2:测试不存在的表字段

修改productexample.java如下(数据库中字段为pid,无id,故先将pid改为id测试不存在字段编译过程):

package com.zhrb.springcloud.entity;
import java.util.arraylist;
import java.util.list;
/**
 * @classname productexample
 * @description todo
  * @author administrator
 * @date 2019/9/20 9:07
 * @version
  */ public class productexample {
    /**
 * this field was generated by mybatis generator. * this field corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected string orderbyclause;
    /**
 * this field was generated by mybatis generator. * this field corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected boolean distinct;
    /**
 * this field was generated by mybatis generator. * this field corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected list<criteria> oredcriteria;
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public productexample() {
        oredcriteria = new arraylist<criteria>();
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void setorderbyclause(string orderbyclause) {
        this.orderbyclause = orderbyclause;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public string getorderbyclause() {
        return orderbyclause;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void setdistinct(boolean distinct) {
        this.distinct = distinct;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public boolean isdistinct() {
        return distinct;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public list<criteria> getoredcriteria() {
        return oredcriteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void or(criteria criteria) {
        oredcriteria.add(criteria);
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public criteria or() {
        criteria criteria = createcriteriainternal();
        oredcriteria.add(criteria);
        return criteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public criteria createcriteria() {
        criteria criteria = createcriteriainternal();
        if (oredcriteria.size() == 0) {
            oredcriteria.add(criteria);
        }
        return criteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected criteria createcriteriainternal() {
        criteria criteria = new criteria();
        return criteria;
    }
    /**
 * this method was generated by mybatis generator. * this method corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public void clear() {
        oredcriteria.clear();
        orderbyclause = null;
        distinct = false;
    }
    /**
 * this class was generated by mybatis generator. * this class corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  protected abstract static class generatedcriteria {
        protected list<criterion> criteria;
        protected generatedcriteria() {
            super();
            criteria = new arraylist<criterion>();
        }
        public boolean isvalid() {
            return criteria.size() > 0;
        }
        public list<criterion> getallcriteria() {
            return criteria;
        }
        public list<criterion> getcriteria() {
            return criteria;
        }
        protected void addcriterion(string condition) {
            if (condition == null) {
                throw new runtimeexception("value for condition cannot be null");
            }
            criteria.add(new criterion(condition));
        }
        protected void addcriterion(string condition, object value, string property) {
            if (value == null) {
                throw new runtimeexception("value for " + property + " cannot be null");
            }
            criteria.add(new criterion(condition, value));
        }
        protected void addcriterion(string condition, object value1, object value2, string property) {
            if (value1 == null || value2 == null) {
                throw new runtimeexception("between values for " + property + " cannot be null");
            }
            criteria.add(new criterion(condition, value1, value2));
        }
        public criteria andidisnull() {
            addcriterion("id is null");
            return (criteria) this;
        }
        public criteria andidisnotnull() {
            addcriterion("id is not null");
            return (criteria) this;
        }
        public criteria andidequalto(string value) {
            addcriterion("id =", value, "id");
            return (criteria) this;
        }
        public criteria andidnotequalto(string value) {
            addcriterion("id <>", value, "id");
            return (criteria) this;
        }
        public criteria andidgreaterthan(string value) {
            addcriterion("id >", value, "id");
            return (criteria) this;
        }
        public criteria andidgreaterthanorequalto(string value) {
            addcriterion("id >=", value, "id");
            return (criteria) this;
        }
        public criteria andidlessthan(string value) {
            addcriterion("id <", value, "id");
            return (criteria) this;
        }
        public criteria andidlessthanorequalto(string value) {
            addcriterion("id <=", value, "id");
            return (criteria) this;
        }
        public criteria andidlike(string value) {
            addcriterion("id like", value, "id");
            return (criteria) this;
        }
        public criteria andidnotlike(string value) {
            addcriterion("id not like", value, "id");
            return (criteria) this;
        }
        public criteria andidin(list<string> values) {
            addcriterion("id in", values, "id");
            return (criteria) this;
        }
        public criteria andidnotin(list<string> values) {
            addcriterion("id not in", values, "id");
            return (criteria) this;
        }
        public criteria andidbetween(string value1, string value2) {
            addcriterion("id between", value1, value2, "id");
            return (criteria) this;
        }
        public criteria andidnotbetween(string value1, string value2) {
            addcriterion("id not between", value1, value2, "id");
            return (criteria) this;
        }
    }
    /**
 * this class was generated by mybatis generator. * this class corresponds to the database table cpt_dls_config * * @mbggenerated do_not_delete_during_merge
 */  public static class criteria extends generatedcriteria {
        protected criteria() {
            super();
        }
    }
    /**
 * this class was generated by mybatis generator. * this class corresponds to the database table cpt_dls_config * * @mbggenerated
  */
  public static class criterion {
        private string condition;
        private object value;
        private object secondvalue;
        private boolean novalue;
        private boolean singlevalue;
        private boolean betweenvalue;
        private boolean listvalue;
        private string typehandler;
        public string getcondition() {
            return condition;
        }
        public object getvalue() {
            return value;
        }
        public object getsecondvalue() {
            return secondvalue;
        }
        public boolean isnovalue() {
            return novalue;
        }
        public boolean issinglevalue() {
            return singlevalue;
        }
        public boolean isbetweenvalue() {
            return betweenvalue;
        }
        public boolean islistvalue() {
            return listvalue;
        }
        public string gettypehandler() {
            return typehandler;
        }
        protected criterion(string condition) {
            super();
            this.condition = condition;
            this.typehandler = null;
            this.novalue = true;
        }
        protected criterion(string condition, object value, string typehandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.typehandler = typehandler;
            if (value instanceof list<?>) {
                this.listvalue = true;
            } else {
                this.singlevalue = true;
            }
        }
        protected criterion(string condition, object value) {
            this(condition, value, null);
        }
        protected criterion(string condition, object value, object secondvalue, string typehandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.secondvalue = secondvalue;
            this.typehandler = typehandler;
            this.betweenvalue = true;
        }
        protected criterion(string condition, object value, object secondvalue) {
            this(condition, value, secondvalue, null);
        }
    }
}

测试结果如下:

MyBatis Generator生成的$ sql是否存在注入风险详解

可以看到,编译出错,证明此时虽然用的是$取值,也经过了预编译,继续看下面。

测试3:like注入测试1

代码及结果截图如下:

MyBatis Generator生成的$ sql是否存在注入风险详解

MyBatis Generator生成的$ sql是否存在注入风险详解

从上面的图可以得知:

此种注入,在封装criteria时把传入的参数整体当做一个对象然后传递下去,本次测试如上图1,打了两个断点,但是没执行到第二个断点处即中断执行,后台日志报错,证明此种注入sql有误无法正常执行。

测试3:like注入测试2

代码及结果截图如下:

MyBatis Generator生成的$ sql是否存在注入风险详解

MyBatis Generator生成的$ sql是否存在注入风险详解

like注入测试1中我们debug可以看到参数似乎拼接方式有误,那么本次注入即正常注入方式,debug看参数,如果将

andidlike 值设置为:‘1' or ‘1=1'

数据上执行的sql理论上是:

select * from product where pid like '1' or '1=1';

在数据库中执行此条sql结果如下:

MyBatis Generator生成的$ sql是否存在注入风险详解

但是demo执行查询结果为空,并且控制台报错,证明此种注入亦不能注入成功。

结论

经以上demo测试,此种$获取值不会受到sql注入的影响,常规sql注入失败。

附录

数据库表结构:

/*
navicat mysql data transfer
source server         : bwg-104.225.147.76
source server version : 50644
source host           : 104.225.147.76:3306
source database       : springcloud_db01
target server type    : mysql
target server version : 50644
file encoding         : 65001
date: 2019-09-20 10:23:41
*/
set foreign_key_checks=0;
-- ----------------------------
-- table structure for product
-- ----------------------------
drop table if exists `product`;
create table `product` (
  `pid` bigint(20) not null auto_increment,
  `product_name` varchar(50) default null,
  `db_source` varchar(50) default null,
  primary key (`pid`)
) engine=innodb auto_increment=7 default charset=utf8;
-- ----------------------------
-- records of product
-- ----------------------------
insert into `product` values ('1', '手机', 'springcloud_db01');
insert into `product` values ('2', '冰箱', 'springcloud_db01');
insert into `product` values ('3', '电脑', 'springcloud_db01');
insert into `product` values ('4', '洗衣机', 'springcloud_db01');
insert into `product` values ('5', '电视', 'springcloud_db01');
insert into `product` values ('6', '音响', 'springcloud_db01');

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。