Go语言实践模式 - 函数选项模式(Functional Options Pattern)大家好,我是小白,有点黑的那个白 。
最近遇到一个问题,因为业务需求,需要对接第三方平台.
而三方平台提供的一些HTTP(S)接口都有统一的密钥生成规则要求.
为此我们封装了一个独立的包 xxx-go-sdk 以便维护和对接使用.
其中核心的部分是自定义HTTP Client,如下:
一些平台会要求appKey/appSecret等信息,所以Client结构体就变成了这样,这时参数还比较少, 而且是必填的参数 , 我们可以提供构造函数来明确指定 。
看起来很满足,但是当我们需要增加一个 Timeout 参数来控制超时呢?
或许你会说这还不简单 , 像下面一样再加一个参数呗
那再加些其他的参数呢?那构造函数的参数是不是又长又串 , 而且每个参数不一定是必须的,有些参数我们又会考虑默认值的问题 。
为此,勤劳但尚未致富的 gophers 们使用了总结一种实践模式
首先提取所有需要的参数到一个独立的结构体 Options,当然你也可以用 Configs 啥的.
然后为每个参数提供设置函数
这样我们就为每个参数设置了独立的设置函数 。返回值func(*Options)看着有点不友好,我们提取下定义为单个Option调整一下代码
当我们需要添加更多的参数时,只需要在 Options 添加新的参数并添加新参数的设置函数即可 。
比如现在要添加新的参数 Timeout
这样后续不管新增多少参数,只需要新增配置项并添加独立的设置函数即可轻松扩展,并且不会影响原有函数的参数顺序和个数位置等 。
至此,每个选项是区分开来了,那么怎么作用到我们的 Client 结构体上呢?
首先,配置选项都被提取到了 Options 结构体重,所以我们需要调整一下 Client 结构体的参数
其次,每一个选项函数返回 Option,那么任意多个就是 ...Option,我们调整一下构造函数 NewClient 的参数形式 , 改为可变参数,不再局限于固定顺序的几个参数 。
然后循环遍历每个选项函数 , 来生成Client结构体的完整配置选项 。
那么怎么调用呢?对于调用方而已,直接在调用构造函数NewClient()的参数内添加自己需要的设置函数(WithXXX)即可
当需要设置超时参数,直接添加 WithTimeout即可,比如设置3秒的超时
配置选项的位置可以任意设置 , 不需要受常规的固定参数顺序约束 。
可以看到,这种实践模式主要作用于配置选项 , 利用函数支持的特性来实现的,为此得名 Functional Options Pattern,优美的中国话叫做「函数选项模式」 。
最后, 我们总结回顾一下在Go语言中函数选项模式的优缺点
GO语言(二十九):模糊测试(下)-语料库文件以特殊格式编码 。这是种子语料库和生成语料库的相同格式 。
下面是一个语料库文件的例子:
第一行用于通知模糊引擎文件的编码版本 。虽然目前没有计划未来版本的编码格式,但设计必须支持这种可能性 。
下面的每一行都是构成语料库条目的值,如果需要,可以直接复制到 Go 代码中 。
在上面的示例中,我们在 a []byte后跟一个int64 。这些类型必须按顺序与模糊测试参数完全匹配 。这些类型的模糊目标如下所示:
指定您自己的种子语料库值的最简单方法是使用该 (*testing.F).Add方法 。在上面的示例中,它看起来像这样:
但是,您可能有较大的二进制文件,您不希望将其作为代码复制到您的测试中 , 而是作为单独的种子语料库条目保留在 testdata/fuzz/{FuzzTestName} 目录中 。golang.org/x/tools/cmd/file2fuzz 上的file2fuzz工具可用于将这些二进制文件转换为为[]byte.
要使用此工具:
语料库条目:语料库中的一个输入,可以在模糊测试时使用 。这可以是特殊格式的文件,也可以是对 (*testing.F).Add 。
覆盖指导:一种模糊测试方法 , 它使用代码覆盖范围的扩展来确定哪些语料库条目值得保留以备将来使用 。
失败的输入:失败的输入是一个语料库条目,当针对模糊目标运行时会导致错误或恐慌 。
fuzz target:模糊测试的目标功能,在模糊测试时对语料库条目和生成的值执行 。它通过将函数传递给 (*testing.F).Fuzz实现 。
fuzz test:测试文件中的一个被命名为func FuzzXxx(*testing.F)的函数,可用于模糊测试 。
fuzzing:一种自动化测试,它不断地操纵程序的输入,以发现代码可能容易受到的错误或漏洞等问题 。
fuzzing arguments:将传递给 模糊测试目标的参数,并由mutator进行变异 。
fuzzing engine:一个管理fuzzing的工具,包括维护语料库、调用mutator、识别新的覆盖率和报告失败 。
生成的语料库:由模糊引擎随时间维护的语料库,同时模糊测试以跟踪进度 。它存储在$GOCACHE/fuzz 中 。这些条目仅在模糊测试时使用 。
mutator:一种在模糊测试时使用的工具,它在将语料库条目传递给模糊目标之前随机操作它们 。
package:同一目录下编译在一起的源文件的集合 。
种子语料库:用户提供的用于模糊测试的语料库,可用于指导模糊引擎 。它由 f.Add 在模糊测试中调用提供的语料库条目以及包内 testdata/fuzz/{FuzzTestName} 目录中的文件组成 。这些条目默认使用go test运行,无论是否进行模糊测试 。
测试文件:格式为 xxx_test.go 的文件,可能包含测试、基准、示例和模糊测试 。
漏洞:代码中的安全敏感漏洞,可以被攻击者利用 。
一学就会,手把手教你用Go语言调用智能合约智能合约调用是实现一个 DApp 的关键,一个完整的 DApp 包括前端、后端、智能合约及区块 链系统,智能合约的调用是连接区块链与前后端的关键 。
我们先来了解一下智能合约调用的基础原理 。智能合约运行在以太坊节点的 EVM 中 。因此要 想调用合约必须要访问某个节点 。
以后端程序为例 , 后端服务若想连接节点有两种可能,一种是双 方在同一主机,此时后端连接节点可以采用 本地 IPC(Inter-Process Communication,进 程间通信)机制,也可以采用 RPC(Remote Procedure Call,远程过程调用)机制;另 一种情况是双方不在同一台主机,此时只能采用 RPC 机制进行通信 。
提到 RPC,读者应该对 Geth 启动参数有点印象,Geth 启动时可以选择开启 RPC 服务,对应的 默认服务端口是 8545 。。
接着 , 我们来了解一下智能合约运行的过程 。
智能合约的运行过程是后端服务连接某节点,将 智能合约的调用(交易)发送给节点 , 节点在验证了交易的合法性后进行全网广播,被矿工打包到 区块中代表此交易得到确认,至此交易才算完成 。
就像数据库一样,每个区块链平台都会提供主流 开发语言的 SDK(Software Development Kit,软件开发工具包) , 由于 Geth 本身就是用 Go 语言 编写的,因此若想使用 Go 语言连接节点、发交易,直接在工程内导入 go-ethereum(Geth 源码) 包就可以了,剩下的问题就是流程和 API 的事情了 。
总结一下,智能合约被调用的两个关键点是节点和 SDK 。
由于 IPC 要求后端与节点必须在同一主机,所以很多时候开发者都会采用 RPC 模式 。除了 RPC,以太坊也为开发者提供了 json- rpc 接口,本文就不展开讨论了 。
接下来介绍如何使用 Go 语言,借助 go-ethereum 源码库来实现智能合约的调用 。这是有固定 步骤的,我们先来说一下总体步骤,以下面的合约为例 。
步骤 01:编译合约,获取合约 ABI(Application Binary Interface,应用二进制接口) 。单击【ABI】按钮拷贝合约 ABI 信息,将其粘贴到文件 calldemo.abi 中(可使用 Go 语言IDE 创建该文件,文件名可自定义,后缀最好使用 abi) 。
最好能将 calldemo.abi 单独保存在一个目录下,输入“ls”命令只能看到 calldemo.abi 文件 , 参 考效果如下:
步骤 02:获得合约地址 。注意要将合约部署到 Geth 节点 。因此 Environment 选择为 Web3 Provider 。
在【Environment】选项框中选择“Web3 Provider”,然后单击【Deploy】按钮 。
部署后,获得合约地址为:0xa09209c28AEf59a4653b905792a9a910E78E7407 。
步骤 03:利用 abigen 工具(Geth 工具包内的可执行程序)编译智能合约为 Go 代码 。abigen 工具的作用是将 abi 文件转换为 Go 代码,命令如下:
其中各参数的含义如下 。(1)abi:是指定传入的 abi 文件 。(2)type:是指定输出文件中的基本结构类型 。(3)pkg:指定输出文件 package 名称 。(4)out:指定输出文件名 。执行后,将在代码目录下看到 funcdemo.go 文件,读者可以打开该文件欣赏一下,注意不要修改它 。
步骤 04:创建 main.go,填入如下代码 。注意代码中 HexToAddress 函数内要传入该合约部署后的地址,此地址在步骤 01 中获得 。
步骤 04:设置 go mod , 以便工程自动识别 。
前面有所提及,若要使用 Go 语言调用智能合约,需要下载 go-ethereum 工程,可以使用下面 的指令:
该指令会自动将 go-ethereum 下载到“$GOPATH/src/github.com/ethereum/go-ethereum”,这样还算 不错 。不过,Go 语言自 1.11 版本后,增加了 module 管理工程的模式 。只要设置好了 go mod,下载 依赖工程的事情就不必关心了 。
接下来设置 module 生效和 GOPROXY,命令如下:
在项目工程内,执行初始化,calldemo 可以自定义名称 。
步骤 05:运行代码 。执行代码,将看到下面的效果,以及最终输出的 2020 。
上述输出信息中,可以看到 Go 语言会自动下载依赖文件,这就是 go mod 的神奇之处 。看到 2020 , 相信读者也知道运行结果是正确的了 。
请教?。?/h2>可读 有两种说法
1 是指 文件属性是 -R 的(文件可读属性)
2 指 文件是可视化编辑的,譬如 .txt、.html文件等,都是可以直接读写的 , 二进制文件、.exe文件就是不可读文件
可执行文件一般指 .exe、.com的文件 , 是可以独立执行完成预定任务的一个程序
什么是数据库?
数据库是以某种文件结构存储的一系列信息表,这种文件结构使您能够访问这些表、选择表中的列、对表进行排序以及根据各种标准选择行 。数据库通常有多个 索引与这些表中的许多列相关联,所以我们能尽可能快地访问这些表 。
以员工记录为例,您可以设想一个含有员工姓名、地址、工资、扣税以及津贴等内容的表 。让我们考虑一下这些内容可能如何组织在一起 。您可以设想一个表包含员工姓名、地址和电话号码 。您希望保存的其它信息可能包括工资、工资范围、上次加薪时间、下次加薪时间、员工业绩评定等内容 。
这些内容是否应保存在一个表格中?几乎可以肯定不应该如此 。不同类别的员工的工资范围可能没有区别;这样,您可以仅将员工类型储存在员工记录表中,而将工资范围储存在另一个表中 , 通过类型编号与这个表关联 。考虑以下情况:
Key Lastname SalaryType SalaryType Min Max
1 Adams 2 1 30000 45000
2 Johnson 1 2 45000 60000
3 Smyth 3 3 60000 75000
4 Tully 1
5 Wolff 2
SalaryType 列中的数据引用第二个表 。我们可以想象出许多种这样的表,如用于存储居住城市和每个城市的税值、健康计划扣除金额等的表 。每个表都有一个主键列(如上面两个表中最左边的列)和若干数据列 。在数据库中建立表格既是一门艺术,也是一门科学 。这些表的结构由它们的范式指出 。我们通常说表属于1NF、2NF 或 3NF 。
第一范式:表中的每个表元应该只有一个值(永远不可能是一个数组) 。(1NF)
第二范式:满足 1NF,并且每一个非主键列完全依赖于主键列 。这表示主键和该行中的剩余表元之间是 1 对 1 的关系 。(2NF)
第三范式:满足 2NF,并且所有非主键列是互相独立的 。任何一个数据列中包含的值都不能从其他列的数据计算得到 。(3NF)
现在,几乎所有的数据库都是基于“第三范式 (3NF)”创建的 。这意味着通常都有相当多的表,每个表中的信息列都相对较少 。
从数据库中获取数据
假设我们希望生成一个包含员工及其工资范围的表,在我们设计的一个练习中将使用这个表 。这个表格不是直接存在在数据库中,但可以通过向数据库发出一个查询来构建它 。我们希望得到如下所示的一个表:
Name Min Max
Tully $30,000.00 $45,000.00
Johnson $30,000.00 $45,000.00
Wolff $45,000.00 $60,000.00
Adams $45,000.00 $60,000.00
Smyth $60,000.00 $75,000.00
我们发现 , 获得这些表的查询形式如下所示
SELECT DISTINCTROW Employees.Name, SalaryRanges.Min,
SalaryRanges.Max FROM Employees INNER JOIN SalaryRanges ON Employees.SalaryKey = SalaryRanges.SalaryKey
ORDER BY SalaryRanges.Min;
这种语言称为结构化查询语言,即 SQL,而且它是几乎目前所有数据库都可以使用的一种语言 。SQL-92 标准被认为是一种基础标准,而且已更新多次 。
数据库的种类
PC 上的数据库,如 dBase、Borland Paradox、Microsoft Access 和 FoxBase 。
数据库服务器:IBM DB/2、Microsoft SQL Server、 Oracle、Sybase、SQLBase 和 XDB 。
所有这些数据库产品都支持多种相对类似的 SQL 方言,因此,所有数据库最初看起来好象可以互换 。每种数据库都有不同的性能特征,而且每一种都有不同的用户界面和编程接口 。
ODBC
如果我们能够以某种方式编写不依赖于特定厂商的数据库的代码,并且能够不改变自己的调用程序即可从这些数据库中得到相同的结果 , 那将是一件很好的事 。如果我们可以仅为所有这些数据库编写一些封装,使它们具有相似的编程接口,这种对数据库编程独立于供应商的特性将很容易实现 。
什么是 JDBC?
JDBC 是对 ODBC API 进行的一种面向对象的封装和重新设计 , 它易于学习和使用,并且它真正能够使您编写不依赖厂商的代码,用以查询和操纵数据库 。尽管它与所有 Java API 一样,都是面向对象的,但它并不是很高级别的对象集.
除 Microsoft 之外,多数厂商都采用了 JDBC,并为其数据库提供了 JDBC 驱动程序;这使您可轻松地真正编写几乎完全不依赖数据库的代码 。另外,JavaSoft 和 Intersolv 已开发了一种称为 JDBC-ODBC Bridge 的产品,可使您连接还没有直接的 JDBC 驱动程序的数据库 。支持 JDBC 的所有数据库必须至少可以支持 SQL-92 标准 。这在很大程度上实现了跨数据库和平台的可移植性 。
安装和使用 JDBC
JDBC 的类都被归到 java.sql 包中,在安装 Java JDK 1.4时会自动安装 。然而 , 如果您想使用 JDBC-ODBC 桥 。JDBC-ODBC 驱动程序可从 Sun 的 Java 网站 () 轻松地找到并下载 。在您扩充并安装了这个驱动程序后,必须执行下列步骤:
将 \jdbc-odbc\classes; 路径添加到您的 PATH 环境变量中 。
将 \jdbc-odbc\classes; 路径添加到您的 CLASSPATH 环境变量中 。
JDBC 驱动程序的类型
Java 程序连接数据库的方法实际上有四种:
1. JDBC-ODBC 桥和 ODBC 驱动程序 -- 在这种方式下,这是一个本地解决方案,因为 ODBC 驱动程序和桥代码必须出现在用户的每台机器中 。从根本上说这是一个临时解决方案 。
2. 本机代码和 Java 驱动程序 -- 它用另一个本地解决方案(该平台上的 Java 可调用的本机代码)取代 ODBC 和 JDBC-ODBC 桥 。
3. JDBC 网络的纯 Java 驱动程序 -- 由 Java 驱动程序翻译的 JDBC 形成传送给服务器的独立协议 。然后,服务器可连接任何数量的数据库 。这种方法使您可能从客户机 Applet 中调用服务器,并将结果返回到您的 Applet 。在这种情况下 , 中间件软件提供商可提供服务器 。
4. 本机协议 Java 驱动程序 -- Java 驱动程序直接转换为该数据库的协议并进行调用 。这种方法也可以通过网络使用,而且可以在 Web 浏览器的 Applet 中显示结果 。在这种情况下,每个数据库厂商将提供驱动程序 。
如果您希望编写代码来处理 PC 客户机数据库 , 如 dBase、Foxbase 或 Access,则您可能会使用第一种方法,并且拥有用户机器上的所有代码 。更大的客户机-服务器数据库产品(如 IBM 的 DB2)已提供了第 3 级别的驱动程序 。
两层模型和三层模型
当数据库和查询它的应用程序在同一台机器上,而且没有服务器代码的干预时,我们将生成的程序称为两层模型 。一层是应用程序 , 而另一层是数据库 。在 JDBC-ODBC 桥系统中通常是这种情况 。
当一个应用程序或 applet 调用服务器,服务器再去调用数据库时,我们称其为三层模型 。当您调用称为“服务器”的程序时通常是这种情况 。
编写 JDBC 代码访问数据库
用 ODBC 注册您的数据库
连接数据库
所有与数据库有关的对象和方法都在 java.sql 包中,因此在使用 JDBC 的程序中必须加入 "import java.sql.* " 。JDBC 要连接 ODBC 数据库,您必须首先加载 JDBC-ODBC 桥驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
该语句加载驱动程序,并创建该类的一个实例 。然后,要连接一个特定的数据库,您必须创建 Connect 类的一个实例,并使用 URL 语法连接数据库 。
String url = "jdbc:odbc:Northwind";
Connection con = DriverManager.getConnection(url);
请注意 , 您使用的数据库名是您在 ODBC 设置面板中输入的“数据源”名称 。
URL 语法可能因数据库类型的不同而变化极大 。
jdbc:subprotocol:subname
第一组字符代表连接协议,并且始终是 jdbc 。还可能有一个子协议,在此处 , 子协议被指定为 odbc 。它规定了一类数据库的连通性机制 。如果您要连接其它机器上的数据库服务器,可能也要指定该机器和一个子目录:
jdbc:bark//doggie/elliott
最后,您可能要指定用户名和口令 , 作为连接字符串的一部分:
jdbc:bark//doggie/elliot;UID=GoodDog;PWD=woof
访问MSSQL Server方法:(驱动程序需要:msutil.jar,msbase.jar,mssqlServer.jar)
DBDriver=com.microsoft.jdbc.sqlserver.SQLServerDriver
URL=jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=demo
username=sa
password=
maxcon=10
mincon=1
poolName=SkyDev
利用我们开发的数据库类,使用方法如下:
DbObject DbO = new DbObject(new SqlServerConnectionFactory("localhost",
1433, "demo", "sa", ""));
Connection con = DbO.getConnection();
//类代码(不含连接工厂实现)
package skydev.modules.data;
public final class SqlServerConnectionFactory
extends ConnectionFactory {
private final String dbDriver =
"com.microsoft.jdbc.sqlserver.SQLServerDriver";
private String host;
private int port;
private String databaseName;
public SqlServerConnectionFactory() {
super.setDriverName(dbDriver);
}
/**
*
* @param host 数据库所在的主机名:如"localhost"
* @param port SQL服务器运行的端口号,如果使用缺省值 1433,传入一个负数即可
* @param databaseName 数据库名称
* @param userName 用户名
* @param password 口令
*/
public SqlServerConnectionFactory(String host,
int port,
String databaseName,
String userName,
String password) {
this.setHost(host);
this.setPort(port);
this.setDatabaseName(databaseName);
this.setUserName(userName);
this.setPassword(password);
init();
}
private void init() {
super.setDriverName(dbDriver);
super.setUrl("jdbc:microsoft:sqlserver://"host.trim()":"
new Integer(port).toString()";DatabaseName="
databaseName.trim());
//super.setUrl("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=demo");
}
……
//------------------------------------------------------------------------------------
访问MySQL的方法:
DBDriver=com.mysql.jdbc.Driver
URL=jdbc:mysql://localhost/demo
username=
password=
maxcon=5
mincon=1
poolName=zhengmao
访问数据库
一旦连接到数据库,就可以请求表名以及表列的名称和内容等信息,而且您可以运行 SQL 语句来查询数据库或者添加或修改其内容 。可用来从数据库中获取信息的对象有:
DatabaseMetaData 有关整个数据库的信息:表名、表的索引、数据库产品的名称和版本、数据库支持的操作 。
ResultSet 关于某个表的信息或一个查询的结果 。您必须逐行访问数据行 , 但是您可以任何顺序访问列 。
ResultSetMetaData 有关 ResultSet 中列的名称和类型的信息 。
尽管每个对象都有大量的方法让您获得数据库元素的极为详细的信息,但在每个对象中都有几种主要的方法使您可获得数据的最重要信息 。然而,如果您希望看到比此处更多的信息,建议您学习文档以获得其余方法的说明 。
ResultSet
ResultSet 对象是 JDBC 中最重要的单个对象 。从本质上讲 , 它是对一个一般宽度和未知长度的表的一种抽象 。几乎所有的方法和查询都将数据作为 ResultSet 返回 。ResultSet 包含任意数量的命名列,您可以按名称访问这些列 。它还包含一个或多个行 , 您可以按顺序自上而下逐一访问 。在您使用 ResultSet 之前,必须查询它包含多少个列 。此信息存储在 ResultSetMetaData 对象中 。
//从元数据中获得列数
ResultSetMetaData rsmd;
rsmd = results.getMetaData();
numCols = rsmd.getColumnCount();
当您获得一个 ResultSet 时,它正好指向第一行之前的位置 。您可以使用 next() 方法得到其他每一行,当没有更多行时,该方法会返回 false 。由于从数据库中获取数据可能会导致错误,您必须始终将结果集处理语句包括在一个 try 块中 。
您可以多种形式获取 ResultSet 中的数据,这取决于每个列中存储的数据类型 。另外,您可以按列序号或列名获取列的内容 。请注意,列序号从 1 开始,而不是从 0 开始 。ResultSet 对象的一些最常用方法如下所示 。
getInt(int); 将序号为 int 的列的内容作为整数返回 。
getInt(String); 将名称为 String 的列的内容作为整数返回 。
getFloat(int); 将序号为 int 的列的内容作为一个 float 型数返回 。
getFloat(String); 将名称为 String 的列的内容作为 float 型数返回 。
getDate(int); 将序号为 int 的列的内容作为日期返回 。
getDate(String); 将名称为 String 的列的内容作为日期返回 。
next(); 将行指针移到下一行 。如果没有剩余行 , 则返回 false 。
Close(); 关闭结果集 。
getMetaData(); 返回 ResultSetMetaData 对象 。
ResultSetMetaData
您使用 getMetaData() 方法从 ResultSet 中获取 ResultSetMetaData 对象 。您可以使用此对象获得列的数目和类型以及每一列的名称 。
getColumnCount(); 返回 ResultSet 中的列数 。
getColumnName(int); 返回列序号为 int 的列名 。
getColumnLabel(int); 返回此列暗含的标签 。
isCurrency(int); 如果此列包含带有货币单位的一个数字,则返回 true 。
isReadOnly(int); 如果此列为只读,则返回 true 。
isAutoIncrement(int); 如果此列自动递增,则返回 true 。这类列通常为键,而且始终是只读的 。
getColumnType(int); 返回此列的 SQL 数据类型 。这些数据类型包括
BIGINT
BINARY
BIT
CHAR
DATE
DECIMAL
DOUBLE
FLOAT
INTEGER
LONGVARBINARY
LONGVARCHAR
NULL
NUMERIC
OTHER
REAL
SMALLINT
TIME
TIMESTAMP
TINYINT
VARBINARY
VARCHAR
DatabaseMetaData
DatabaseMetaData 对象可为您提供整个数据库的信息 。您主要用它获取数据库中表的名称 , 以及表中列的名称 。由于不同的数据库支持不同的 SQL 变体,因此,也有多种方法查询数据库支持哪些 SQL 方法 。
getCatalogs() 返回该数据库中的信息目录列表 。使用 JDBC-ODBC Bridge 驱动程序,您可以获得用 ODBC 注册的数据库列表 。这很少用于 JDBC-ODBC 数据库 。
getTables(catalog, schema,tableNames, columnNames) 返回表名与 tableNames 相符而且列名与 columnNames 相符的所有表的说明 。
getColumns(catalog, schema,tableNames, columnNames) 返回表名与 tableNames 相符而且列名与 columnNames 相符的所有表列说明 。
getURL(); 获得您所连接的 URL 名称 。
getDriverName(); 获得您所连接的数据库驱动程序的名称 。
获取有关表的信息
您可以使用 DataBaseMetaData 的 getTables() 方法来获取数据库中表的信息 。这个方法有如下4个 String 参数:
results =dma.getTables(catalog, schema, tablemask, types[]);
其中参数的意义是:
Catalog 要在其中查找表名的目录名 。对于 JDBC-ODBC 数据库以及许多其他数据库而言,可将其设置为 null 。这些数据库的目录项实际上是它在文件系统中的绝对路径名称 。
Schema 要包括的数据库“方案” 。许多数据库不支持方案,而对另一些数据库而言 , 它代表数据库所有者的用户名 。一般将它设置为 null 。
Tablemask 一个掩码,用来描述您要检索的表的名称 。如果您希望检索所有表名,则将其设为通配符 % 。请注意,SQL 中的通配符是 % 符号,而不是一般 PC 用户的 * 符号 。
types[] 这是描述您要检索的表的类型的 String 数组 。数据库中通常包括许多用于内部处理的表,而对作为用户的您没什么价值 。如果它是空值,则您会得到所有这些表 。如果您将其设为包含字符串“TABLES”的单元素数组,您将仅获得对用户有用的表格 。
一个简单的 JDBC 程序
我们已经学习了 JDBC 的所有基本功能,现在我们可以编写一个简单的程序,该程序打开数据库,打印它的表名以及某一表列的内容,然后对该数据库执行查询 。此程序如下所示:
package skydevkit;
import java.sql.*;
public class JdbcOdbc_test {
ResultSet results;
ResultSetMetaData rsmd;
DatabaseMetaData dma;
Connection con;
public JdbcOdbc_test() throws SQLException {
String url = "jdbc:odbc:Northwind";
try {
//加载 JDBC-ODBC 桥驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con = DriverManager.getConnection(url);//连接数据库
dma = con.getMetaData();//获取数据库的元数据
System.out.println("Connected to:"dma.getURL());
System.out.println("Driver "dma.getDriverName());
} catch (Exception e) {
System.out.println(e);
}
try {
Statement stmt = con.createStatement();
results = stmt.executeQuery("select * from 客户;");
ResultSetMetaData resultMetaData = https://www.04ip.com/post/results.getMetaData();
int cols = resultMetaData.getColumnCount();
String resultRow = "";
for (int i = 1; icols; i) {
resultRow= resultMetaData.getColumnName(i)";";
}
System.out.println(resultRow);
while (results.next()) {
resultRow = "";
for (int i = 1; icols; i) {
try {
resultRow= results.getString(i)";";
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}
}
System.out.println(resultRow);
}
} catch (Exception e) {
System.out.println("query exception");
} finally {
results.close();
}
}
}
补充高级内容
关于调用SQLServer存储过程的例子:(用到了我们开发的数据库连接类)
CREATE PROCEDURE [dbo].[sp_getStudentByName](@name char(10))
AS
Select * from Students where [Name]=@name
GO
DbObject DbO = new DbObject(new SqlServerConnectionFactory("localhost",
1433, "demo", "sa", ""));
Connection con = DbO.getConnection();
CallableStatement pstmt = null;
System.out.println("TestDB1()............");
/* try {
pstmt = con.prepareCall("{call sp_getStudentById(?)}");
pstmt.setInt(1, 1);
}*/
try {
pstmt = con.prepareCall("{call sp_getStudentByName(?)}"); //注意参数如何传递
pstmt.setString(1, "Tom");
}
……
使用输出参数:
CREATE PROCEDURE [dbo].[sp_insertStudent](@name char(10),@age int,@id int OUTPUT) AS
insert into Students([Name],[Age]) values (@name,@age)
select @id=@@IDENTITY
GO
try {
pstmt = con.prepareCall("{call sp_insertStudent(?,?,?)}");
pstmt.setString(1, "zengqingsong");
pstmt.setInt(2, 22);
pstmt.registerOutParameter(3, Types.INTEGER);
pstmt.executeUpdate();
int id = pstmt.getInt(3);
System.out.println(id);
}
使用返回参数的例子:
CREATE PROCEDURE [dbo].[sp_insertStudent](@name char(10),@age int,@id int OUTPUT) AS
insert into Students([Name],[Age]) values (@name,@age)
select @id=@@IDENTITY –测试输出参数
return 30 –测试返回30
GO
try {
pstmt = con.prepareCall("{?=call sp_insertStudent(?,?,?)}");
pstmt.setString(2, "zengqingsong");
pstmt.setInt(3, 22);
pstmt.registerOutParameter(4, Types.INTEGER);
pstmt.registerOutParameter(1, Types.INTEGER);
int ret = pstmt.executeUpdate(); //执行影响的行数
int ret2 = pstmt.getInt(1); //返回参数(输出参数)
int id = pstmt.getInt(4); //输出参数
System.out.println(ret);
System.out.println(ret2);
System.out.println(id);
go语言中实现切片(slice)的三种方式定义一个切片 , 然后让切片去引用一个已经创建好的数组 。基本语法如下:
索引1:切片引用的起始元素位
索引2:切片只引用该元素位之前的元素
例程如下:
在该方法中,我们未指定容量cap,这里的值为5是系统定义的 。
在方法一中,可以用arr数组名来操控数组中的元素,也可以通过slice切片来操控数组中的元素 。切片是直接引用数组,数组是事先存在的 , 程序员是可见的 。
通过 make 来创建切片,基本语法如下:
make函数第三个参数cap即容量是可选的,如果一定要自己注明的话,要注意保证cap≥len 。
用该方法可以 指定切片的大小(len)和容量(cap)
例程如下:
由于未赋值系统默认将元素值置为0,即:
数值类型数组:默认值为 0
字符串数组:默认值为 ""
bool数组:默认值为 false
在方法二中,通过make方式创建的切片对应的数组是由make底层维护 , 对外不可见,即只能通过slice去访问各个元素 。
定义一个切片,直接就指定具体数组 , 使用原理类似于make的方式 。
例程如下:
【go语言指定参数缺省值 go语言null】关于go语言指定参数缺省值和go语言null的介绍到此就结束了 , 不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。
推荐阅读
- 超薄硬盘怎么磨,超薄硬盘怎么磨损
- 张掖专注sap技术指导,张掖专注sap技术指导中心
- 加密货币和区块链交易,精通区块链编程加密货币原理,方法和应用开发
- mysql中or怎么表示 mysql orcal
- 苹果鸿蒙系统新消息,苹果系统升级鸿蒙
- 关于经营游戏下载,有关经营的游戏
- java后台调用js代码 java如何调用js
- mongodb添加全局用户名,mongodb创建用户名和密码
- 抖音拍摄怎么挂小程序,抖音拍视频怎么挂小程序