vs2010 oracle数据库实例教程,vs2010 net oracle编程

Build a .NET Application on the Oracle Database with Microsoft

Visual Studio 2010

by John Paul Cook

Learn the basic yet essential processes involved in building a

.NET application that uses an Oracle database.

Published June

2011

With the popularity of Microsoft's .NET Framework, many

developers are hungry for information about the best means of

integrating .NET applications with Oracle—not only in terms of

basic connectivity, but also in relationship to effective and

efficient application development using Microsoft Visual Studio

2010. (The Visual Studio 2005/2008 version of this article is found

here. )

In this article, I'll explain the basic yet essential processes

involved in building a C# or Visual Basic .NET application that

uses an Oracle database, including:

How to add project references to support Oracle class libraries

in your .NET project

How to create Oracle Database connection strings

How to work with Connection, Command, and DataReader

objects

You will have the opportunity to apply what you have learned in

three practice labs, ranging in difficulty from the relatively

simple to the more complex. If you are already familiar with

building .NET applications for Oracle Database with Visual Studio

2005/2008, the experience with Visual Studio 2010 is very

similar.

For information and labs about how to secure your application,

see my article "Securing

a .NET Application on the Oracle Database." (Also, see

the OTN .NET Developer Center for

technical articles covering a range of Oracle .NET application

lifecycle issues.)

Note that the free Oracle Developer Tools for Visual Studio,

available for download from OTN, provides a

Visual Studio add-in that makes the development of .NET apps on

Oracle much easier and more intuitive. That subject is beyond our

scope here, however; see the Oracle Developer Tools for Visual Studio

Product Center for more information.

.NET Data Provider

In addition to basic Oracle client connectivity software, .NET

applications require the use of what is known as a managed data

provider (where "managed" refers to code managed by the .NET

framework). The data provider is the layer between the .NET

application code and the Oracle client connectivity software. In

almost every case, the best performance is achieved by using a

provider optimized for a specific database platform instead of the

generic .NET OLE DB data provider.

Oracle, Microsoft, and third-party vendors all offer .NET data

providers optimized for an Oracle database. Oracle and Microsoft

make their Oracle data providers available for free. Microsoft's

provider for the .NET Framework is deprecated. Oracle continues to

support and develop their .NET data provider, Oracle Data Provider

for .NET (ODP.NET). In this article, we will use ODP.NET, which is

included with the Oracle Database or as a separate download.

ODP.NET provides standard ADO.NET data access, while exposing

Oracle database-specific features, such as XML DB, data access

performance optimizations, and Real Application Clusters load

balancing and fast connection failover. The current ODP.NET

version, 11.2, supports connecting to Oracle Database 9i

Release 2 servers and higher versions. The

database server can be on Windows, Linux, UNIX, or any other

operating system platform Oracle database supports.

When ODP.NET and Oracle client software are installed,

application development using Visual Studio can begin. It's a good

idea to confirm client connectivity before starting development. If

you can connect to Oracle Database using Oracle client software,

such as SQL*Plus on the same machine as Visual Studio, then your

Oracle client-side software is properly installed and

configured.

If you are new to Oracle, see the section "Installing .NET

Products" in the Oracle Database 2 Day Developer's

Guide for background information regarding

installing and configuring ODP.NET specifically, or to the Oracle Database Documentation

Library for general information about Oracle

Database.

Creating a Project in Visual Studio 2010

Let’s create an ODP.NET application that retrieves data from the

Oracle database. Later, we’ll see how to perform

error handling with ODP.NET and handle an additional data retrieval

scenario.

After starting Visual Studio, the first task is to create a

project. You can either click New Project as shown

below or select File | New | Project.

A New Project dialog box appears. On the left

side of the dialog box under Installed Templates,

select the programming language of your choice. In our example,

Visual Basic was chosen. On the middle of the dialog, choose a

project template. To keep things simple, a Windows Forms

Application is selected.

You'll want to specify meaningful names for the project name (we

used OraWinApp) and the solution name (we used

OraWinApp). A solution contains one or more

projects. When a solution contains only one project, many people

use the same name for both. Notice that there is a dropdown list

box allowing you to specify which version of the .NET Framework you

want to target. If you are writing applications for an older

version of the .NET Framework, you should select the appropriate

version from the dropdown list. Click the Ok

button to continue.

Adding a Reference

Because our project must connect to an Oracle database, it is

necessary to add a reference to the ODP.NET DLL containing the data

provider of our choice. Within the Solution Explorer on the right

side of Visual Studio, select the project name, right click and

select Add Reference. Alternatively, you can go to

the menu bar and select Project and then select

Add Reference.

The Add Reference dialog box appears. Select

the .NET tab. Visual Studio will construct a list

of .NET components available for you to add to your

project. This may take several

seconds. When complete, you can click on the

Component Name column to alphabetize the component

list.

ODP.NET is found under the Oracle.DataAccess component name.

Select Oracle.DataAccess from the list, then click

the OK button to make the ODP.NET data provider

known to your project. Be sure to select the correction version.

Since this is a .NET 4 project, the 4.112.2.0 version of

Oracle.DataAccess was chosen here, but you can chose any ODP.NET

version beginning with 4.

Visual Basic/C# Statements

After adding references, it is standard practice to add Visual

Basic Imports statements or C# using statements. Technically, these

statements are not required, but they do allow you to refer to

database objects without using lengthy, fully qualified names.

By convention, these statements appear at or near the top of a

code file, before the namespace or class declaration.

Imports

Oracle.DataAccess.Client ' Visual Basic ODP.NET Oracle managed

provider

using

Oracle.DataAccess.Client; // C# ODP.NET Oracle managed

provider

If you added the reference, Intellisense will help you complete

the addition of an Imports or using statement as shown in Figure

5.

Connection Strings and Objects

An Oracle connection string is inseparable from Oracle names

resolution. In this article, we will connect to Oracle’s sample HR

schema with user id “hr” and password “hr”. The tnsnames.ora file

is an Oracle network configuration file that defines database

addresses for establishing connections. Suppose we had a database

alias of OraDb defined in a tnsnames.ora file as follows:

OraDb=

(DESCRIPTION=

(ADDRESS_LIST=

(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521))

)

(CONNECT_DATA=

(SERVER=DEDICATED)

(SERVICE_NAME=ORCL)

)

)

The OraDb alias defines the database address connection information

for the client. To use the OraDb alias defined in the tnsnames.ora

file shown above, you would use the following syntax:

Dim oradb As String = "Data

Source=OraDb;User Id=hr;Password=hr;" ' Visual Basic

string oradb = "Data

Source=OraDb;User Id=hr;Password=hr;"; // C#

You can modify the connection string to obviate the need for the

tnsnames.ora file, however. Simply replace the name of the alias

with how it would be defined in a tnsnames.ora file. The database

alias in this article is specific to my database setup. (Click

here for more information about

creating a database alias for your database.)

' Visual Basic

Dim oradb As String = "Data Source=(DESCRIPTION=" _

+ "(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521))" _

+ "(CONNECT_DATA=(SERVICE_NAME=ORCL)));" _

+ "User Id=hr;Password=hr;"

// C#

string oradb = "Data Source=(DESCRIPTION="

+ "(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521))"

+ "(CONNECT_DATA=(SERVICE_NAME=ORCL)));"

+ "User Id=hr;Password=hr;";

As you can see above, the username and password are embedded in the

connection string in clear text. This is the simplest approach to

creating a connection string. However, the clear text approach is

undesirable from a security perspective. In particular, you must

understand that compiled .NET application code is only marginally

more secure than the clear text source code files. It is very easy

to decompile .NET DLL and EXE files and view the original clear

text contents. (Encryption is in fact the appropriate solution, but

that subject would be a quite lengthy digression from our

discussion here.)

Next, you must instantiate a connection object from the

connection class. The connection string must be associated with the

connection object.

Dim conn As New

OracleConnection(oradb) ' Visual Basic

OracleConnection conn =

new OracleConnection(oradb); // C#

Notice that the connection string is associated with the connection

object by being passed through the object's constructor, which is

overloaded. The constructor's other overload allows the following

alternative syntax:

Dim conn As New

OracleConnection() ' Visual Basic

conn.ConnectionString = oradb

OracleConnection conn =

new OracleConnection(); // C#

conn.ConnectionString = oradb;

After associating a connection string with a connection object, use

the Open method to make the actual connection.

conn.Open() ' Visual

Basic

conn.Open(); //

C#

We'll cover error handling later.

Command Object

The command object is used to specify the SQL command text that is

executed, either a SQL string or a stored procedure. Similar to the

connection object, it must be instantiated from its class and it

has an overloaded constructor. In this sample, ODP.NET will perform

a SQL query to return the department_name from the departments

table where the department_id is 10.

Dim sql As String =

"select department_name from departments where department_id = 10"

' Visual Basic

Dim cmd As New OracleCommand(sql, conn)

cmd.CommandType = CommandType.Text

string sql = " select

department_name from departments where department_id = 10"; //

C#

OracleCommand cmd = new OracleCommand(sql, conn);

cmd.CommandType = CommandType.Text;

Using different overloads, the syntax can be structured slightly

differently. The command object has methods for executing the

command text, which will be seen in the next section. Different

methods are appropriate for different types of SQL commands.

Retrieving a Scalar Value

Retrieving data from the database can be accomplished by

instantiating an OracleDataReader object and using the

OracleCommand’s ExecuteReader method, which returns an

OracleDataReader object. Returned data is accessible by passing

either the column name or zero-based column ordinal to the

OracleDataReader.

Dim dr As

OracleDataReader = cmd.ExecuteReader() ' Visual Basic

dr.Read()

Label1.Text = dr.Item("department_name") ' retrieve by column

name

Label1.Text = dr.Item(0) ' retrieve the first column in the select

list

Label1.Text = dr.GetString(0) ' return a .NET data type

Label1.Text = dr.GetOracleString(0) ' return an Oracle data

type

C# developers must use accessor type methods for retrieving data.

There are typed accessors for returning .NET native data types and

others for returning native Oracle data types, all of which are

available in C#, Visual Basic, or any other .NET language.

Zero-based ordinals are passed to the accessors to specify which

column to return.

OracleDataReader dr =

cmd.ExecuteReader(); // C#

dr.Read();

label1.Text = dr["department_name"].ToString(); // C# retrieve by

column name

label1.Text = dr.GetString(0).ToString(); //

return a .NET data type

label1.Text = dr.GetOracleString(0).ToString(); // return an Oracle data type

In this simplified example, the returned value of department_name

is a string and is used to set the value of the label control's

text property, which is also a string. But if department_id, which

is not a string, had been retrieved instead, there would be a data

type mismatch. The .NET runtime attempts to implicitly convert from

one data type to another when the source and destination data types

don't match. Sometimes the data types are incompatible and the

implicit conversion fails, throwing an exception. But even when it

works, it's still better to use explicit data type conversions

instead of implicit data type conversion.

An explicit cast to integer is shown below:

Label1.Text =

CStr(dr.Item("department_id")) ' Visual Basic integer to string

cast

C# is not as forgiving as Visual Basic on implicit conversions.

You'll find yourself doing explicit conversions:

label1.Text =

dr.GetInt16("department_id").ToString(); // C#

You can explicitly cast scalar values as well as arrays.

Close and Dispose

Either the connection object's Close or the Dispose method should

be called to close the connection to the database. The Dispose

method calls the Close method implicitly.

conn.Close()

' Visual Basic

conn.Dispose() ' Visual Basic

conn.Close();

// C#

conn.Dispose(); // C#

You don't have to explicitly call Close or Dispose if you use VB's

Using keyword or C#'s using keyword.

using (OracleConnection conn

= new OracleConnection(oradb)) // C#

{

conn.Open();

OracleCommand cmd = new OracleCommand();

cmd.Connection = conn;

cmd.CommandText = "select department_name from departments where

department_id = 10";

cmd.CommandType = CommandType.Text;

OracleDataReader dr = cmd.ExecuteReader();

dr.Read();

label1.Text = dr.GetString(0);

}

In addition, OracleCommand includes a Dispose method;

OracleDataReader includes a Close and Dispose

method. Closing and disposing .NET objects free

up system resources, ensuring more efficient application

performance, which is especially important under high load

conditions. You can experiment with some of the concepts we've

learned here in Lab 1 (Retrieving Data from the Database) and Lab 2 (Adding Interactivity).

Error Handling

When an error occurs, .NET applications should gracefully handle

the error and inform the user with a meaningful

message. Try-Catch-Finally structured error

handling is a part of .NET languages. Here is a relatively

minimalist example of using the Try-Catch-Finally syntax:

' Visual Basic

Try

conn.Open()

Dim cmd As New OracleCommand

cmd.Connection = conn

cmd.CommandText = "select department_name from departments "

_

+ "where department_id = " + TextBox1.Text

cmd.CommandType = CommandType.Text

If dr.Read() Then

Label1.Text = dr.Item("department_name") ' or use dr.Item(0)

End If

Catch ex As Exception ' catches any error

MessageBox.Show(ex.Message.ToString())

Finally

' In a real

application, put cleanup code here.

End Try

// C#

try

{

conn.Open();

OracleCommand cmd = new OracleCommand();

cmd.Connection = conn;

cmd.CommandText = "select department_name from departments where

department_id = " + textBox1.Text;

cmd.CommandType = CommandType.Text;

if (dr.Read()) // C#

{

label1.Text

= dr["department_name"].ToString();

// or use dr.GetOracleString(0).ToString()

}

}

catch (Exception ex) // catches any error

{

MessageBox.Show(ex.Message.ToString());

}

finally

{

// In a real

application, put cleanup code here.

}

Although this approach will gracefully capture any errors in

attempting to get data from the database, it is not user friendly.

For example, look at the following message displayed when the

database is unavailable:

An ORA-12545 is quite meaningful for an Oracle DBA or developer,

but not for an end user. A better solution is to add an additional

Catch statement to trap for the most common database errors and

provide user-friendly messages.

' Visual Basic

Catch ex As OracleException ' catches only Oracle errors

Select Case

ex.Number

Case 1

MessageBox.Show("Error attempting to insert duplicate data.")

Case 12545

MessageBox.Show("The database is unavailable.")

Case Else

MessageBox.Show("Database error: " + ex.Message.ToString())

End

Select

Catch ex As Exception ' catches any error

MessageBox.Show(ex.Message.ToString())

// C#

catch (OracleException ex) // catches only Oracle errors

{

switch

(ex.Number)

{

case 1:

MessageBox.Show("Error attempting to insert duplicate

data.");

break;

case 12545:

MessageBox.Show("The database is unavailable.");

break;

default:

MessageBox.Show("Database error: " + ex.Message.ToString());

break;

}

}

catch (Exception ex) // catches any error not previously

caught

{

MessageBox.Show(ex.Message.ToString());

}

Notice the two Catch statements in the code sample above. If there

aren't any Oracle errors to catch, the first Catch statement branch

is skipped, leaving any other non-Oracle error to be caught by the

second Catch statement. Catch statements must be ordered in the

code from most specific to most general. After implementing the

user-friendly exception handling code, the ORA-12545 error message

appears as follows:

The Finally code block is always executed regardless of whether

or not an error occurred. It is where cleanup code belongs. If you

don't use Using or using, you should dispose your connection and

other objects in the Finally code block.

Retrieving Multiple Values Using a DataReader

Thus far our examples have only showed how to retrieve a single

value. An OracleDataReader can retrieve values for multiple columns

and multiple rows. First consider a multiple column, single row

query:

select department_id,

department_name, location_id from departments where department_id =

10

To keep things simple for this article, we are using a single

table, the departments table. To obtain the values of the columns,

either zero-based ordinals or column names can be used. Ordinals

are relative to the order in the query. Thus, the location_id

column's value can be retrieved in Visual Basic by using either

dr.Item(2) or dr.Item("location_id").

Here is a code snippet that concatenates the department_name and

location_id columns from the previous query:

Label1.Text = "The " +

dr.Item("department_name") + " department is in " _

+ dr.Item("location_id") ' VB

label1.Text = "The " +

dr["department_name"].ToString() + " department is in " +

dr["location_id"].ToString(); // C#

Now consider a query that returns multiple rows:

select department_id, department_name,

location_id from departments

To process multiple rows returned from an OracleDataReader, some

type of looping construct is needed. Furthermore, a control that

can display multiple rows is desirable. An OracleDataReader is a

forward-only, read-only cursor, so it can't be bound to an

updateable or fully scrollable control such as a Windows Forms

DataGrid control. An OracleDataReader is compatible with a ListBox

control, as the following code snippet illustrates:

While dr.Read() ' Visual

Basic

ListBox1.Items.Add("The " +

dr.Item("department_name") _

+ " department is in " + dr.Item("location_id"))

End While

while (dr.Read()) //

C#

{

listBox1.Items.Add("The " +

dr["department_name"].ToString() + " department is in " +

dr["location_id"].ToString());

}

Lab 3 (Retrieve Multiple Columns and Rows with an

OracleDataReader) highlights some of these concepts.

Building and Running on Windows x64

When running Visual Studio 2010 on a Windows x64 operating

system, you can use the Configuration Manager to

change the target platform type. Select the solution in the

Solution Explorer, right-click, and select

Configuration Manager.

Summary

This article has introduced you to the process of accessing

Oracle databases using .NET programming languages. You should now

have the capability to connect to the database and retrieve

multiple columns and rows.

Lab 1: Retrieving Data

from the Database

We begin with the requirement that you've created a project and

added a reference as shown previously in this article.

Continue by adding a button control and a label control to the

Windows form. Be sure to leave room above the controls to allow

additions that will be made in Lab 2.

Add code to retrieve data from the Oracle database and display the

results on the form. Put the code in a click event handler for the

button. The easiest way to get started with this task is to double

click the button because it will create a stub for the event

handler.

Add Visual Basic Imports statements before the Public Class

declaration or C# using statements before the namespace

declaration.

Imports

Oracle.DataAccess.Client ' Visual Basic, ODP.NET Oracle managed

provider

using

Oracle.DataAccess.Client; // C#, ODP.NET Oracle managed

provider

Add the Visual Basic version of the click event handler code

between the Private Sub and End Sub statements (be sure to replace

ORASRVR with your server's host name and replace the service name

entry with your database’s service name):

Dim oradb As String =

"Data Source=(DESCRIPTION=(ADDRESS_LIST=" _

+

"(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))" _

+

"(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));" _

+ "User Id=hr;Password=hr;"

Dim conn As New

OracleConnection(oradb) ' Visual Basic

conn.Open()

Dim cmd As New

OracleCommand

cmd.Connection = conn

cmd.CommandText = _

"select department_name from departments where department_id =

10"

cmd.CommandType = CommandType.Text

Dim dr As

OracleDataReader = cmd.ExecuteReader()

dr.Read() ' replace this statement in next

lab

Label1.Text = dr.Item("department_name") ' or dr.Item(0), remove in

next lab

dr.Dispose()

cmd.Dispose()

conn.Dispose()

Add the following C# code to the click event handler between the {

and } curly braces for the button's click event handler (be sure to

replace ORASRVR with your server's host name and replace the

service name entry with your database’s service name):

string oradb = "Data

Source=(DESCRIPTION=(ADDRESS_LIST="

+

"(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))"

+

"(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));"

+ "User Id=hr;Password=hr;";

OracleConnection conn =

new OracleConnection(oradb); // C#

conn.Open();

OracleCommand cmd = new

OracleCommand();

cmd.Connection = conn;

cmd.CommandText =

"select department_name from departments where department_id =

10";

cmd.CommandType = CommandType.Text;

OracleDataReader dr =

cmd.ExecuteReader();

dr.Read(); // replace this statement in next

lab

label1.Text = dr["department_name"].ToString(); // remove in next lab

dr.Dispose();

cmd.Dispose();

conn.Dispose();

Run the application. Click the button. You should see the

following:

Lab 2: Adding Interactivity

Now that the basics of database access are implemented in the

code, the next step is to add interactivity to the application.

Instead of running the hard coded query, a textbox control can be

added to accept a user input for the department number (i.e.,

department_id).

Add a textbox control and another label control to the form as

shown below. Set the text property of the Label2 control to “Enter

department_id:” and make sure that the Text property of TextBox1

isn't set to anything.

Modify the code that defines the select string:

cmd.CommandText = _

"select

department_name from departments where department_id = "_

+

TextBox1.Text 'VB

cmd.CommandText = "select

department_name from departments where department_id = " +

textBox1.Text; // C#

Run the application. Test the application by entering 10 for

the department_id. Retest the application by entering an invalid

department_id (e.g., 12). The application will abort.

Modify your code to prevent an error when an invalid

department_id is entered. Recall that the ExecuteReader method

actually returns an object. Replace the line containing dr.Read

with all of the following statements.

If dr.Read() Then ' Visual

Basic

Label1.Text

= dr.Item("department_id").ToString()

Else

Label1.Text

= "department_id not found"

End If

if (dr.Read()) //

C#

{

label1.Text

= dr["department_id"].ToString();;

}

else

{

label1.Text

= "department_id not found";

}

Test the application by entering a department_id that does not

exist. Now the application no longer aborts. Enter the letter A

instead of a number and click the button. The application aborts.

Clearly, our application needs a better approach to handling

errors.

Although it could be argued that the application should not allow

the user to make invalid inputs that would cause an error,

ultimately the application must have robust error handling added.

Not all errors are preventable, so error handling must be

implemented.

Lab 3: Retrieve Multiple

Columns and Rows with an OracleDataReader

Now that a single value has been retrieved, the next step is to

retrieve multiple columns and rows with an OracleDataReader. A

ListBox control is added to the form to display the results.

Add a ListBox control to the form. Resize the control to fill

most of the width of the form as shown below.

Remove the where clause from the query and add the additional

columns:

cmd.CommandText = _

"select

department_id, department_name, location_id from departments" '

VB

cmd.CommandText = "select

department_id, department_name, location_id from departments "; //

C#

The query results will be read in a while loop and will

populate the ListBox control. Modify your Visual Basic code to look

like this, making the appropriate changes to the host and service

name for your database:

Dim oradb As String =

"Data Source=(DESCRIPTION=(ADDRESS_LIST=" _

+

"(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))" _

+

"(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));" _

+ "User Id=hr;Password=hr;"

Dim conn As New

OracleConnection(oradb) ' Visual Basic

conn.Open()

Dim cmd As New

OracleCommand

cmd.Connection = conn

cmd.CommandText = _

"select

department_id, department_name, location_id from departments" '

VB

cmd.CommandType = CommandType.Text

Dim dr As

OracleDataReader = cmd.ExecuteReader()

While dr.Read()

ListBox1.Items.Add("The " + dr.Item("department_name") + _

" department is in " + dr.Item("location_id").ToString())

End While

dr.Dispose()

cmd.Dispose()

conn.Dispose()

Modify your C# code to look like this:

string oradb = "Data Source=(DESCRIPTION=(ADDRESS_LIST="

+

"(ADDRESS=(PROTOCOL=TCP)(HOST=ORASRVR)(PORT=1521)))"

+

"(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)));"

+ "User Id=hr;Password=hr;";

OracleConnection conn =

new OracleConnection(oradb); // C#

conn.Open();

OracleCommand cmd = new

OracleCommand();

cmd.Connection = conn;

cmd.CommandText = "select department_id, department_name,

location_id from departments.168";

cmd.CommandType = CommandType.Text;

OracleDataReader dr =

cmd.ExecuteReader();

while (dr.Read())

{

listBox1.Items.Add("The " +

dr["department_name"].ToString() +

" department is in " + dr["location_id"].ToString());

}

dr.Dispose();

cmd.Dispose();

conn.Dispose();

Run the application. The ListBox should be populated with all

of the department names and locations from the departments table.

The code downloads have error handling implemented.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值