Firebird一款很牛X的数据库

Borland InterBase和开源的FireBird是一个强大的、支持SQL语言的数据库, 她经常用于嵌入式开发和特定的应用软件中。聪明的开发者和架构师花些时间详细的了解下IB/FB就会发现,她确实有多处超越MSSQLserver的优势。这些优势包括: 在混合读写环境下更加卓越的并发性; 更灵活的触发器支持; 更快的灾难恢复; 更简单的事件管理; 更多的部署选择; 跨平台支持; 小巧; 系统要求更低; 更短的培训时间; 更低的培训费用; 更低的许可费用;(FireBird完全免费)

本文将详细讨论这些优势。 今天的嵌入式和分布式数据库应用创造了一种环境——由短时间的读事务和更新事务 (典型的如数据录入系统)以及长时间读事务(如制作报表和数据分析)这两种情况组成。当数据分析要求马上在此刻得到一个一致的数据视图时,MSSQLServer必须加锁来防止其他用户存取正在分析的数据。 IB/FB的数据库引擎专门设计成能够及时的为你的数据提供一个一致的快照,而不会阻塞其他用户的读和更新。在IB/FB中,读操作绝不会阻塞写操作,写操作只有当两个事务试图在同一时刻更新同一行时阻塞写操作。另外,IB /FB的并发模型是完全可预测的。使用IB/FB,绝不会有MSSQLServer里类似锁的任意升级导致整个表的存取被拒绝麻烦。 IB/FB 拥有嵌入式或需要远程部署的应用所需要的所有关键特性。 你的开发团队很容易学习和使用,很容易部署且在产品中几乎不需要维护。IB只有只有MSSQLServer最小安装大小的六分之一(FB更小),却提供了 SMP支持,跨平台支持,先进的基于成本的查询优化,行级锁,从服务器灾难中即时恢复,事务支持在任何时刻及时提供一致快照的隔离级别,丰富的SQL方言,before和after两种触发器,完整的触发器触发顺序控制,存储过程,在线备份,在线修改元数据,复制,以及在客户端的应用程序中触发来自数据库触发器的事件。 IB在三方面降低项目中的成本: 1、IB的授权许可费用比MSSQLServer低(FB是完全免费开源的); 2、需要更少的时间培训。一个MSSQLServer2000的DBA认证至少需要22天的课堂培训。 IB/FB学起来是如此容易以至于其培训课程只需5天,就可以使一个完全的数据库新手达到能够为IB/FB数据库提供信赖支持的程度。那些已经对基本的数据库管理熟悉的人会发现,不时查询一下Interbase的文档就是所需要的一切了。 3、开发人员不必花时间寻找创造性的方法来写代码解决数据库的限制, 比如锁冲突,锁升级,缺少的"before"触发器,有限的触发器触发顺序控制和需要的事件。

为你的项目选择合适的数据库 建一个你的数据库项目需要的属性列表不是难事。 但仅依靠一个简单的特性列表来评估数据库是不够的。为你的应用程序选择一个正确的数据库时最关键的一步是调查在你的应用程序将会遇到的真实情形中,你所考虑的数据库的行为。本文调查了IB和MSSQLServer在许多情况下的行为,在当今的商业环境中你很有可能面对这些情况。

数据的一致性与并发性 假设你有一个存货管理系统,用于跟踪许多仓库中的产品条目。 在系统运行时,你的应用程序必须要出一个存货估价报表。使用读提交(read committed)的事务隔离,会发生下面的一系列事件: 1、开始一个将要合计价值的读事务,从各个仓库收集条目; 2、这个读事务扫描Abilene仓库的所有记录; 3、另一个用户开始一个更新事物,从Abilene仓库移动1000金条到San Antonio仓库; 4、更新事务提交; 5、读事务读到San Antonio仓库的记录。这个读事务现在就把1000金条计算了两次, 一次在Abilene仓库,另一次在San Antonio仓库。 在 MSSQLServer中,通过给读事务使用Serializable(连续读)事务隔离很容易避免这个问题。 Serializable隔离模式保护你的事务在其生存期内不会看到由其他用户作出的改变。然而,要达到这种效果,MSSQLServer要么锁住整个表,要么在WHERE语句跨越的所有覆盖值的索引上放一系列锁 (引自Microsoft SQL Server 2000, Microsoft Press,799页)。 虽然这些锁比表锁限制少,但仍有很多本来不必要的行被禁止插入。考虑下面的SELECT语句: SELECT * FROM CUSTOMER WHERE CITY >= 'Charleston' AND CITY <= 'Los Alamos' 假设在CITY列的索引中覆盖的WHERE语句的范围是Abilene, Detroit, and San Francisco这些节点,那么这些节点都会被锁住。不幸的是,这将意味着你不能插入这样一列,它的值大于Abilene而小于Charleston,即使WHERE语句没有包含这一行,因为它在锁的覆盖范围内。同样的原因,你也不能插入其值大于Los Alamos而小于San Francisco的行(引自Microsoft SQL Server 2000, Microsoft Press,776页 )。 虽然数据的一致性达到了,但这也牺牲了并发性, 因为其他用户不能在行锁覆盖的行及表锁覆盖的表上插入和更新的记录。当分析和汇总大量的数据时 ——比如上面的例子,在读事务结束之前,其他用户的插入和更新会一直被阻塞。 在IB/FB中,由于IB的版本引擎机制,这个问题根本就不存在。回到库存估价的例子中,下面是IB/FB的情况: 1、使用快照事务隔离机制,读事务开始; 2、读事务扫描Abilene仓库的记录; 3、另一个用户开始一个更新事务,从Abilene移动1000金条到San Francisco; 4、更新事务发现一个更早的活动事务,于是为需要更新的记录创建新的版本; 5、更新事务提交; 6、读事务读到San Antonio中更新的记录。 读事务看到当前记录的版本是由一个在它之后开始的事务创建的,于是它往回扫描记录的版本,直到它发现一个在它开始时已经提交的版本,并读那个版本。 通过读那些只在读事务开始时已经提交的记录版本, 不用禁止记录的更新,IB/FB就能提供一个逻辑上一致的数据视图。

死锁 假如用户A执行一个SELECT语句读Parts表中的所有行。用户B也SELECT了Parts表的所有行。两个用户都要获得各自所选数据的一个稳定一致的视图。用户A试图更新part=100的记录。用户B试图更新part=101的记录。 MSSQLServer 会使用重复读或serializable事务隔离,这种情况将导致死锁,即使两个用户更新的是不同的行。怎么会呢?A在读记录时得到表上的一个共享锁。B 也一样。当A更新part=100的记录时,必须得到这一行的排他锁,于是把他在表上的共享锁转换成意向排他锁。然而,意向排他锁和B的共享锁冲突,所以无法得到(引自Microsoft SQL Server 2000, Microsoft Press,799页 )。同样,当B要更新part=101的记录时,因为A的共享锁,B也不能把他在表上的共享锁转换成意向排他锁。这就是所谓的转换死锁(见 Microsoft SQL Server 2000, Microsoft Press,776页 )。 在IB/FB中不会发生锁转换。IB /FB只会在更新时锁住个别的行。IB/FB只会发生一种类型的死锁就是循环死锁(所有数据库都存在),也就是当用户A更新并锁住了行100,然后试图更新已经被用户B加锁并更新的行200,同时,用户B也试图更新已经被A加锁的行100。这种情况下,会发生下面两种情况之一。如果有用户在他们事务中指定了NoWait选项,那么当A试图给B已经锁住的行加锁时,会立即返回错误信息,反之亦然。如果两个用户都选择了等待加锁的行,那么锁管理器将检测到死锁并选择一个事务让其回滚。

锁冲突 考虑这样一种情形,当用户A对一行进行了更新操作但没有提交事务,然后A去吃午饭了。用户B执行一个包含此加锁行的SELECT操作。 使用MSSQLServer,用户B的事务将一直等待,直到用户A持有的锁释放为止(MSDN-Locking Architcture at http://msdn.microsoft.com/librar ... c/8_ar_sa2_2sit.asp )。“缺省设置下,没有强制超时期,也没有办法在加锁之前测试出释放的资源是否被锁,除非企图存取数据(潜在得到不确定的阻塞)”(见Microsoft SQL Server 2000 Books Online, LOCK_TIMEOUT Setting)。“为了预防这种不确定的等待,需要设置锁的超时期,使用SET LOCK_TIMEOUT命令,但这个设置会影响连接中所有事务”(见Microsoft SQL Server 2000 Books Online, SET LOCK_TIMEOUT)。 IB/FB限制更少且更灵活。使用快照事务隔离(snapshot),你一直读的是事务开始时已经提交的行的最新版本。使用读提交(read committed)事务隔离,IB/FB给你三种选择: 1、读这一行最新提交的版本即使有未提交的版本存在; 2、等待,直到未提交的版本也提交或回滚,然后读这一行; 3、立即接收到一个异常警告:存在此行的一个未提交版本; 这些设置在事务级别,因此同一连接中,你为某一个事务的所作的设置不会限制到你为其他事务的所作的选择。 锁升级 设想你正在开发一个订单录入系统。订单条目表会包含上百万条记录。你必须能够通过客户类型和销售地域中的条目为某一时期生成销售报表,报表必须基于一致的数据视图。生成年报表将在订单条目表中选择超过百万的记录。 “当一个事务超过升级上限时, MSSQLServer2000会自动升级行锁和页锁。比如,当一个事务需要表中的一些行时, SQLServer自动获得这些行的锁,并在包含那些行的页、表或索引上放置更高级别的意向锁。当事务持有的锁的数量超过其极限时,SQLServer会企图把表上的意向锁变为更强的锁(如意向排他锁转为排他锁).获得更强的锁后,所有此事务持有的页级和行级锁被释放,锁开销减少了。”(见http://msdn.microsoft.com/librar ... c_8_con_7a_5ovi.asp, Lock Escalation )锁升级的结果是整个表对其他用户不再可用。在本例中,记录上的共享锁将升级为一个表上的共享锁。于是其他所有用户都不能更新此表中的任一行。如果要更新一个表中的大量行,那么更新需要的排他锁可能升级为表级锁,以防止其他用户读和更新这张表。 IB/FB的版本体系结构在读记录时不需要任何锁。通过记录的不同版本,一致性的数据视图不需要放置锁,更不会阻塞其他更新操作。IB/FB的锁只是行级别的,且只在更新一行时存在,所以根本不存在锁升级的概念。

触发器的灵活性 当给数据库添加新客户时,系统必须自动指定其销售区域和销售代表。为了指定正确的销售区域,应用程序必须从State表中查找用户所在的州,然后用销售区域和客户的分类代码查找Sales Rep表。理想的解决方案是给Customer表添加一个Before Insert触发器, 在记录插入Customer表之前添加销售区域和销售代表号码。 MSSQLServer没有在事件之前激活的触发器,只能附在 INSERT,UPDATE或DELETE事件之后激活(见Microsoft SQL Server 2000, Microsoft Press,657页)。 为了解决上面提到的问题,可以使用所谓instead-of触发器。这种触发器激活后取代它所附属的事件。在本例中,将激活这种触发器,但那条新的客户记录不会被插入到数据库中。因此,触发器不仅要决定销售区域和销售代表,还要执行把新客户记录插入数据库中的INSERT语句。这使得触发器很复杂,时间也浪费在写触发器上了。 更不幸的是,instead-of触发器还有其他限制。每个事件只能有一个instead-of触发器。不能用多个触发器来模块化你的代码,以便容易维护。Instead-of触发器也不能和某些外键一起使用——这些外键给触发器所依附的事件设置了级联选项。比如,如果某个表有一个设置了级联删除的外键,instead-of触发器就不能出现在这个删除事件中。 IB/FB给INSERT,UPDATE和DELETE同时提供了before与after触发器。每一事件的触发器数量没有限制,在触发器和外键约束之间也没有任何冲突。 同一事件的多个触发器能使代码模块化,便于测试和维护。然而,对于触发器执行的顺序,MSSqlServer只提供了很有限的控制。你能指定某一触发器第一个触发或最后一个触发,但仅此而已。一旦触发器必须独立于触发顺序,那么它们写起来很复杂且不够灵活。 IB/FB可以制定触发器执行的精确顺序。在触发顺序的任一点,随时能够很容易的插入新的触发器。 对于MSSqlServer来说控制触发器中的错误很难。一旦触发器在事件之后触发,撤销触发器执行的INSERT,UPDATE或DELETE操作的唯一方法就是回滚事务。由于一个致命错误或请求回滚事务,触发器内的回滚中止了整批SQL指令,而不仅仅是那些由触发器做的修改(见Microsoft SQL Server 2000, Microsoft Press,687页)。 IB/FB中,若before触发器产生异常,之前发生 INSERT,UPDATE或DELETE将会中止。IB/FB也允许在触发器激活时创建指定的还原点(savepoint)。你可以随时回滚到任一还原点。比如,更新前(before)触发器中创建一个还原点,然后在更新后(after)触发器中回滚到这个还原点,从而使该还原点后的所做的修改(包括触发此触发器的UPDATE本身)撤销了。不只是在存储过程和触发器中,还原点在事务的任何时候都可用。

成本 应用软件也许分布在许多地方或支持许多用户,当使用到数据库时,数据库本身的许可费用会变为项目开支的一个重要部分。下面的表格比较了IB与MSSQLServer2000标准版的费用。IB在每一类中都更加实惠。 (注:由IB开源而来的FB是完全免费且源代码公开的,即使在商业用途中,也是如此) 用户数 CPU个数 Borland InterBase MSSQLserver2000标准版 20 1 2300美元(下同) 4498美元(下同) 20 2 3300 4498 50 1 3700 4999 50 2 4700 9998 50 4 6700 11245 100或200 1 4199 4999 100或200 2 5199 9998 100或200 4 7199 19996

资源需求 减少部署费用的一个方法是通过网络发布你的应用软件。另外,你也许同样希望能减少部署地点的硬件升级所需的开支。 MSSQLServer2000需要“97到270兆的可用硬盘空间,典型安装需要250兆”。Windows2000下需要64兆内存,WindowsXP下需要128兆内存。(见http://www.microsoft.com/sql/evaluation/sysreqs/2000/default.asp) IB完全安装需要不到40兆的硬盘空间。如果你不安装文档和例子,那么安装少于15兆(FB所需更少)。此外在所有平台下,运行IB只需要32兆的内存。

部署与发布 你或许想把数据库服务器和客户端的安装集成到应用软件里,使安装部署更容易。 但你必须使用Microsoft提供的安装包来安装MSSQLServer。“SQLServer的安装程序写注册表,改变系统路径和多处系统设置,创建程序组和用户账户,并为其使用执行基本的初始化配置。安装程序远非仅仅拷贝文件。对于你来说,作为服务或产品的一部分创建自己的程序来安装 SQLServer是不现实的(见Microsoft SQL Server 2000, Microsoft Press,166-167页)。” 与之相比,IB/FB给了你完全的灵活性。你可以使用本身的安装包,也可以用其他安装打包软件,或者干脆自己写安装程序。

MSDE 也许,作为使用MSSQLServer的另一种选择,你会考虑使用MSDE来部署发布应用程序。 MSDE就是SQLServe2000,拥有其所有特性和限制。MSDE还有三个额外的限制。“为了达到最佳性能,有一个限制在五个并发工作量的并发量管理器”, “若超过五工作量的限制,并发管理器会使系统不断的慢下来”(见http://www.microsoft.com/sql/msde/productinfo/features.asp)。每一条工作量是一个连接,如果每一个用户需要两个连接,那么MSDE就只能支持两个用户。MSDE需要44兆的硬盘空间,2000下64兆内存,XP下128内存。(见http://www.microsoft.com/sql/evaluation/sysreqs/2000/default.asp) “MSDE支持2G以下的单个数据库。”——注意不是每个表。这是第二个额外限制。这也就是说你的所有数据,元数据,索引,临时表,存储过程和触发器加一起必须在2G以内。 “MSDE2000包括一些供管理实例的命令”(见http://www.microsoft.com/sql/msde/productinfo/features.asp) ——MSDE不提供任何MSSQLServer的GUI工具来设计和创建数据库,管理服务器,测试查询和调整服务器的性能。 “几个Microsoft的产品有权许可转让使用和重新发布MSDE2000”(见http://www.microsoft.com/sql/msde/productinfo/features.asp) 获得的这些权力很复杂,而且依赖你购买的获得MSDE2000的Microsoft产品。有些产品不包括重新发布的权力。其他能重新发布的需要满足多方面的条件。

特性 下面的表格比较了IB/FB和SQLServer的特性。这个表单并不完全,但是集中了重要的特性,如远程部署的嵌入式应用、长时间读事务间杂着更新事务组成的应用。 特性 InterBase/FireBird SQL Server 事务支持 是 是 SQL支持 是 是 用户自定义函数 是 是 基于成本优化 是 是 提供不会阻塞更新的一致数据快照 是 否 行级锁 是 是 不存在锁升级 是 否 不存在转换死锁 是 否 快照事务隔离 是 是 两段式提交 是 是 支持多用户和单用户 是 是 支持SMP 是 是 存储过程 是 是 before触发器 是 否 after触发器 是 是 触发器触发顺序控制 是 否 触发客户端事件 是 否 自动生成键 是 是 支持所有数据类型取空值 是 是 参照完整性 是 是 在线备份 是 是 在线更改元数据 是 是 复制 是 是 即时灾难恢复 是 否 零维护 是 是 定制安装包 是 否 内存需要 32MB 2000下64MB,XP下128MB 硬盘空间 40MB(包括文档和例子),否则不到15MB 平均250MB

结论 IB/FB是你拥有: 混合读写环境中卓越的并发性; 更灵活的触发器支持; 更快的灾难恢复; 更容易的事件管理; 更多的部署选择; 跨平台支持; 小巧; 系统要求更低; 更短的培训时间; 更低的培训费用; 更实惠的许可费用... IB/FB以最低的成本和最短的时间,提供了创建强大应用所需要的特性。

作者简介:Bill Todd是Database Group, Inc.(Phoenix旁边的一个数据库咨询与开发公司)的总裁。合著过4本数据库编程方面的书籍,发表超过100篇文章。在美国和欧洲的开发者大会上提交了超过20篇论文。

转载于:https://my.oschina.net/u/582827/blog/729289

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Firebird是一个全功能的,强大高效的,轻量级,免维护的数据库。它很容易让您从单用户,单数据库升级到企业级的应用。 一个firebird数据库服务器能够管理多个独立的数据库,每一个数据库同时可支持多个客户端连结。 关键特性:支持原子性,并发性,隔离性等概念。 MGA:支持事务的多个版本功能, 存储过程: 使用PSQL(Procedure SQL),你可以创建强大的存储过程来处理服务上的所有数据,你可以使用select Stored Procedure的形式,使用存储过程,以得到一个虚拟的表结构的结果。这样的话,你就可以很容易的在报表中使用它。 事件:存储过程和触发器可以引发事件,这个事件可以被客户端程序监听到 生成子:生成子也称为序列,它可以很容易的实现自动增加的字段。它是一个INT64的长度,因此,它可以用在一个事务中,也可以用在其它很多方面。 只读数据库: 我们可以把数据库存放在CD中,形成一个只读数据库。如果我们的应用程序 也在光盘上,再加上嵌入式的FB数据库服务器,便可以得到一个无与伦比的 CDLIVE(即只用光盘就可以运行起来)应用。 全事务控制: 一个客户端可以存在多个并发的事务。并且每一个事务都可以独立的进行控制,两段提交功能可以保证数据库的一致性。锁优化机制也支持多个事务的保存点。 在线备份: 不需要停止数据库即可进行备份,一个备份进程产生一个数据库当前的快照。因此,用户可以在备份期间持续的工作,即实现24x7(每天24小时,每周7天) 的操作。 触发器: 每一个表可以有多个并发的行级触发器,可以在插入前,插入后,更新前,更新后,删除前,删除后进行触发。我们可以在触发器中写入PSQL语句,默认值,产生异常,firebird现在支持统一触发器,即可以一个触发器中,一次性管理插入,更新,删除的操作。 扩展函数: 我们可以使用C语言,C++,DELPHI写UDF,使用UDF(用户定义函数库)可以很容易的挂入数据库引擎中以扩展我们需要的功能 字符集:Firebird实现了很多国际标准的字符集,包括Unicode。 SQL标准兼容:Firebird 实现了全部SQL92所要求的功能,实现了SQL99最常用的的要求。包括但不限于"FULL/LEFT/RIGHT [OUTER] JOIN , UNION, DISTINCT , 子查询 (IN, EXISTS),内部函数 (AVG, SUM, MIN, MAX, COALESCE, CASE, ..), 主键,外键,唯一索引以及所有通用的数据类型。 Firebird还实现了域,字段级别的约束,视图,异常,规则和权限管理,更多的详细信息,请参考Firebird发布通知和参考手册。 硬件需求: Firebird可以工作最常见的硬件环境中,甚至非常差的硬件中,也能很好的工作,当然,硬件的要求依赖于你想做什么,例如 ,你有多少个并发用户等等。 有效的平台支持: Firebrid在常见的平台上都可运行,如Linux和Windows(包括Windows终端服务器)其它支持的平台包括(MAC OS(苹果机), Solaris及HP-UX) 把数据库从一个平台转到另一个平台,非常的容易,只要备份数据库,然后,再到另一个平台上恢复即可 可连接性: Firebird 支持一系列的连接方法,目前,可以通过原生的DELPHI,C++组件连接,也可以通过ODBC,JDBC,PHP,OLEDB,DbExpress进行连接。原生 的联连提供了直接调用Firebird的API函数库(fbclient.dll/.so)进行调用的能力。 物理限制: Firebird支持非常巨大的数据库数据库可以分成多个物理文件。每个文件的大小依赖于操作系统的限制。当前一个数据库文件最大的理论限制是64T (即64000G),因此,常见的限制通常是操作系统的限制以及磁盘空间的限制。 服务器引擎版本: 当前有三个服务器版本。 标准服务器:每一个客户连接将引发一个服务器进程(支持多处理器) 超级服务器:一相服务器进程模块管理所有的客户端连接,当前不支持多处理器。 嵌入服务器:整个服务器引擎就是一个动态库,只支持本地通过IO进行调用。 但是,所有的服务器都使用一种数据库格式,因此,你可以很方便的在不同的引擎之间共享数据库文件的数据。 协议: Firebird协议使用IPL(interbase public license)和IDPL(Initial Developer's Public License),这种协议类似于Mozilla协议。你可以完全的自由使用并且可以自由的布署在你的客户应用上。 你不需要公开你的源代码。当然,如果你修改和数据库引擎,你应该公布源代码。 工具: 有很多的工具支持Firebird.包括自由的,免费的和商业的。 包括开发工具,管理工具,诊断工具等等。
要下载Firebird数据库,首先需要下载FirebirdSql.Data.FirebirdClient-6.4.0-net452.7z文件。在下载完成后,需要解压该文件,并在C#项目中引用解压后的FirebirdSql.Data.FirebirdClient.dll文件。这样就可以在C#项目中连接Firebird数据库了。 Firebird是一个开源的数据库管理系统,它可以管理多个独立的数据库,并支持多个客户端的连接。你可以使用Firebird来创建任意路径下的数据库,例如:C:\MyFuckingDB.fdb。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Firebird数据库的安装及使用](https://blog.csdn.net/huzhizhewudi/article/details/123613490)[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: 33.333333333333336%"] - *2* [数据库安装FireBird及FBControl、FlameRobin等工具.rar](https://download.csdn.net/download/flyingdove_yphy0/86400148)[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: 33.333333333333336%"] - *3* [安装Firebird数据库及其ODBC驱动程序](https://blog.csdn.net/feichangfriend/article/details/9140973)[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: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值