一键链改使用手册
1. 引言
1.1 编写目的
本文档用于介绍Hyperchain一键链改功能的使用方法。面向的用户为应用开发人员,为其在将现有应用进行”一键链改”或者直接基于一键链改功能进行新应用的开发时作为指导和参考。
1.2背景
作为领先的区块链底层平台,为提升数据使用的便捷程度所提供的数据使用方式,方便区块链服务于更多的业务场景,Hyperchain拟内生支持SQL语句的使用,能够简化用户将数据从普通业务转换为区块链业务应用的适配复杂度。通常,用户只需将原来MySql的JDBC驱动变更为一键链改提供的JDBC驱动,即可完成应用上链。
1.3术语
名词 |
解释 |
|---|---|
JDBC |
Java数据库连接,(Java Database Connectivity,简称JDBC)是 一 种可用于执行 SQL 语句的 Java API。JDBC 为数据库应用开发人 员、数据库前台开发人员提供了一种标准的应用程序设计接口, 使开发人员可以用纯 Java 语言编写完整的数据库应用程序。 |
DDL |
数据定义语言,主要为创建、修 改、删除数据库的逻辑结构,其中包括表结构,视图和索引等。 |
DML |
数据操纵语 言,主要用于数据库中数据的修改,包括添加、删除、修改等。 |
DQL |
数据查询语言,用于数据库中数据的检索查询。 |
2. 安装和初始化
2.1 平台安装
一键链改为Hyperchain平台提供的一个新特性,请确认安装包含一键链改功能特性的Hyperchain平台版本。
2.2 创建“库”
Hyperchain平台支持SQL语句的执行,与MySql存在概念上的差异:
元素 |
描述 |
|---|---|
合约地址 |
区块链上的数据将存储在 一个地址下,由于联盟链的数据为联盟链成员或全链所有,因 此将数据归属于一个用户使用的账户不合适,应参考智能合约 的模式,为多个强关联的数据表创建一个合约地址作为“库”。 |
表 |
一个合约地 址下可以有多张数据表,表用于记录业务数据,应拥有primary key,并于创建时建立索引。 |
列 |
一张数据表内可以有多列,初期不支持对列的修改 |
行值 |
普通的行值,按列的数据规则插入的数据。 |
因此,类似于MySql使用前需要创建一个库,在Hyperchain上也需要进行类似操作先创建一个”库”。其操作方式为通过SDK向区块链平台发起一个创建库请求,示例代码如下(详见litesdk文档):
Account account = accountService.genAccount(Algo.SMRAW);
Transaction transaction = new Transaction.SQLBuilder(account.getAddress()).create().build();
transaction.sign(account);
ReceiptResponse receiptResponse = sqlService.create(transaction).send().polling();
String contractAddress = receiptResponse.getContractAddress();
上述示例中最终得到 contractAddress 即为“库”地址,供后续步骤使用。
3.操作说明
完成Hyperchain平台安装和初始化后,即可开始进行应用的改造。应用改造包括驱动配置改造与应用功能检查
3.1 替换驱动配置
我们提供了一个JDBC驱动,用于替代传统SQL数据库的JDBC驱动。通过对驱动接口的调用,会直接与区块链平台进行交互。
替换驱动配置的步骤为:
替换JDBC class name
一键链改驱动class name为 cn.hyperchain.sql.driver.KVSQLDriver ,将其替换mysql的驱动名称
替换url
数据库的URL设计遵循JDBC规范,如下
其含义如下:
内容 |
含义 |
|---|---|
jdbc |
代表jdbc协议 |
kvsql |
协议实现标识 |
blockchain |
固定字符,当前未保留内容 |
使用的 库名称(具体为库地址,为2.2中创建的结果) |
|
property1 =value1&property2=value2 |
连接属性,可以 将配置项直接写入url,具体配置项可参考下文 |
说明:url中传入的配置项会被通过properties传入的配置项所覆盖。
修改驱动配置项
与MySql JDBC驱动的配置项类似,一键链改JDBC驱动也有自己的配置项,用户可以使用和MySql JDBC驱动配置项相同的方式进行配置,区别是配置项名称有所不同。
配 置项名称 |
配置项说明 |
缺省值 |
最低版 本要求 |
|
|---|---|---|---|---|
基本 |
user |
区块链账户(Account) |
必须配置 |
1.0.0 |
password |
区块链账户加密密码 |
1.0.0 |
||
SDK相关 |
urls |
区块链节点的url列表 |
必须配置 |
1.0.0 |
namespace |
区块链的namespace |
global |
1.0.0 |
|
attempt |
SDK重发次数 |
10 |
1.0.0 |
|
sleepTime |
SDK重发间隔 |
50 |
1.0.0 |
|
stepSize |
SDK重发间隔增长幅度 |
50 |
1.0.0 |
|
sendTCert |
SD K发送交易是否开启证书 |
false |
1.0.0 |
|
sdkCert |
sdkCert证书(字符串) |
1.0.0 |
||
sdkPriv |
sdkPriv(字符串) |
1.0.0 |
||
uniquePub |
uniquePub证书(字符串) |
1.0.0 |
||
u niquePriv |
uniquePriv(字符串) |
1.0.0 |
||
https |
是否开启https |
false |
1.0.0 |
|
tlsCA |
tlsCA证书(字符串) |
1.0.0 |
||
tl sPeerCert |
tlsP eerCert证书(字符串) |
1.0.0 |
||
tl sPeerPriv |
tlsPeerPriv(字符串) |
1.0.0 |
||
rea dSimulate |
是否开启查询 语句为simulate交易( 即所有的select语句走 simulate查询不上链) |
true |
1.0.0 |
|
cfca |
是否使用cfca |
false |
1.0.0 |
|
cf caSdkCert |
cfca sdkCert证书(字符串) |
1.0.0 |
||
cf caSdkPriv |
cfca sdkPriv(字符串) |
1.0.0 |
||
其他 |
dbname |
”库”地址 |
必须配置 |
1.0.0 |
logger |
指定使用的logger类 |
cn. hyperchain. sql.log.Sta ndardLogger |
1.0.0 |
|
p rofileSQL |
是否打印单次调用时间 (向平台请求以及得到 响应的时间)消耗日志 |
false |
1.0.0 |
|
characte rEncoding |
驱 动程序在处理字符串时 应该使用什么字符编码 |
utf-8 |
1.0.0 |
|
co ntinueBat chOnError |
Batch执行 时一条语句执行出错是 否继续执行剩下的语句 |
true |
1.0.0 |
|
gene rateSimpl eParamete rMetadata |
是否 生成简单的参数元数据 |
false |
1.0.0 |
|
pro cessEscap eCodesFor PrepStmts |
是否在prepare statement中处理转义 |
true |
1.0.0 |
|
useStream LengthsIn PrepStmts |
是否使用 PreparedStatement/Res ultSet.setXXXStream() 方 法调用中的流长度参数 |
true |
1.0.0 |
|
emptySt ringsConv ertToZero |
驱动 程序是否应允许从空字 符串字段转换为数值“0” |
true |
1.0.0 |
|
jdbcC ompliantT runcation |
是 否截断数据时抛出异常 |
true |
1.0.0 |
|
padChars WithSpace |
如果结果集列具有 CHAR 类型并且该值未填充 DDL 中为该 列指定的字符数量,驱 动程序是否应该用空格 填充剩余的字符(符合 ANSI) |
false |
1.0.0 |
|
tiny Int1isBit |
驱动程 序是否应该将数据类型 TINYINT(1) 视为 BIT 类型 |
true |
1.0.0 |
|
trans formedBit IsBoolean |
如果驱动程序将 TINYINT(1) 转换为不同的 类型,它是否应该使用 BOOLEAN 而不是 BIT |
false |
1.0.0 |
|
autoDe serialize |
驱动程序是否应该自动 检测和反序列化存储在 BLOB 字段中的对象? |
false |
1.0.0 |
|
blobsA reStrings |
驱 动程序是否应该始终将 BLOB 视为字符串 |
false |
1.0.0 |
|
functio nsNeverRe turnBlobs |
驱动程 序是否应该始终将返回 BLOB 的函 数中的数据视为字符串 |
false |
1.0.0 |
|
clo bCharacte rEncoding |
用于发送和检索 TEXT、MEDIUMTEXT 和 LONGTEXT 值的字符编 码,而不是配置的连接 characterEncoding |
null |
1.0.0 |
|
emulat eLocators |
是 否应该使用定位器模拟 java.sql.Blobs |
false |
1.0.0 |
|
treatU tilDateAs Timestamp |
出于 Prepared Statement.setObject() 的目 的,驱动程序是否应将 java.util.Date 视为 TIMESTAMP? |
true |
1.0.0 |
|
sen dFraction alSeconds |
是否从 TIMESTAMP 秒发送小数部分 |
true |
1.0.0 |
|
s endFracti onalSecon dsForTime |
是否呈现小数秒 |
true |
1.0.0 |
|
yearI sDateType |
是否应该将 MySQL 类型“YEAR”视为 java.sql.Date |
true |
1.0.0 |
|
ze roDateTim eBehavior |
当驱动程 序遇到完全由零组成的 DATETIME 值(MySQL 用于表示无效日期)时 会发生什么?有效值为 “EXCEPTION”、“ROUND” 和“CONVERT_TO_NULL”。 |
EXCEPTION |
1.0.0 |
|
useColum nNamesInF indColumn |
将此属性 设置为“true”将提供与 JDBC-3.0 和早期版本的 JDBC 规范一致的行为 |
false |
1.0.0 |
|
useOldAli asMetadat aBehavior |
驱动程序是否应该 对列和表的“AS”子句使 用旧行为,并且只返回 ResultSetMet aData.getColumnName() 或 ResultSetMe taData.getTableName() 的别名(如果有 )而不是原始列/表名称 |
false |
1.0.0 |
注 :标注为“必须配置”的配置项为使用一键链改功能必须配置的配置项,不管是通过url配置还是properties配置,必须有一个地方要包含。
需要说明的是,任何可以将配置项传入到Driver的connect方法所需要的Properties参数的方式,均可以作为配置项传入的方式,例如,在使用Spring Boot框架时可以通过其默认使用的数据库连接池hikari提供的方式进行配置项传入:
// SpringBoot 项目启动入口
Properties properties = new Properties();
properties.setProperty("spring.datasource.hikari.data-source-properties.urls", "localhost:8081");
String accountJson = "{\"address\":\"2a8dba2c1c991de7d98f3f4ec54327478ec5a0fa\",\"publicKey\":\"04228994bd8b59c25adf142bcbb1296d90710d85f6224889c36dd803bb40c5478332a4c2f14c9d48c09c8557cff7d6a8ff3572835835555fd6c97d23c89cab8d5d\",\"privateKey\":\"5d95ecde330a24c11decc4034f325c3b42e0698f5d0523b67fa64b82e0571af4\",\"version\":\"4.0\",\"algo\":\"0x03\"}";
properties.setProperty("spring.datasource.hikari.data-source-properties.user", accountJson);
// 将properties配置项传入
new SpringApplicationBuilder(DemoApplication.class).properties(properties).run(args);
3.2 检查应用中当前不支持的功能
一键链改JDBC驱动实现了标准的JDBC协议,但由于区块链平台和传统SQL数据库存在差异,部分在传统数据库中(如:MySQL)支持的功能特性并未在Hyperchain中支持或使用语法有些许差异,因此用户在使用一键链改JDBC驱动时需要检查应用中是否有使用到不支持与有差异的特性,并进行更改与规避。
3.2.1 检查JDBC不支持的功能列表
以下特性当前不支持:
不支持的特性 |
修改与规避建议 |
|---|---|
不支持事务 |
建议在应用层进行事务的控制 |
不支持存储过程 |
|
不支持设置事务隔离级别 |
|
不支持Catalog |
|
不支持设置只读模式 |
|
不支持获取Warning |
|
不支持typeMap |
|
不支持setClientInfo |
3.2.2 检查使用的SQL的语法与Mysql的差异性
一键链改辅助用户将基于SQL语句开发的业务应用系统迁移至区块链上,并成为运行在区块链上业务系统。平台已支持的数据类型、运算符、函数、表达式请参考 “Operators & Functions使用手册”,“数据类型Type使用手册”,“Expression使用手册” 。
区块链的数据都将记录在一个地址中,一键链改功能的表数据将记录在一个合约地址中,一个合约地址可记录多个表,因此可将存储表数据的合约地址理解为存储多张表的一个业务数据库。用户需规划库表关系,将表数据写入正确的合约地址下。
平台已支持常用的SQL语句,包括:用于创建表、插入行值、修改行值、删除行值、查询行值。SQL语句表达范式请参考 “DDL语句使用手册”,“DML语句使用手册”,“DQL语句使用手册” 。
在使用本功能进行数据操作时,请注意以下事项:
在区块链中使用SQL语句将通过向链上提交携带拟执行的SQL语句的交易,一个包含子语句的SQL语句被视为一笔交易进行执行。
在对表进行创建时,需明确定义会使用的索引列(主键、索引键)。在表创建后,暂不支持对表结构进行变更、增删索引列、删除表、查询表结构的操作,亦不支持外键的设置。
在对表进行行值定位、行值查询时,建议基于索引列进行查询,否则将触发全表扫描的行为。面对数据规模较大的表,若进行全表扫描则容易导致执行时间较长乃至执行超时的情况。
由于本功能的执行将由区块链完成,因此语句执行后不可回退,执行隔离级别默认为串行执行。平台支持一次性输入多条SQL语句进行执行,多条SQL语句为自动提交模式,不支持使用事务特性控制SQL语句的执行结果。
上述SQL语句相关的使用文档中未明确支持的SQL语句、数据类型、运算及函数皆为暂不支持的功能。
本功能支持联表、并表、多表的操作,但不支持外键的使用,需注意在业务中是否使用了外键。
4. 注意事项
由于hibernate以及当前平台特性的限制,当前不支持hibernate中的 ddl-auto 配置项,请将其设置为 none 。
由于当前不支持事务以及相关的语法(如select … for update;),因此在使用框架(如ORM框架)时不支持依赖事务以及其相关语法的特性,如JPA主键自增策略中的 GenerationType.AUTO 由于其依赖 select … for update; 语法,因此无法使用。
由于区块链系统与MySql的差异,应用通过驱动与区块链平台进行交互时需要进行SDK轮询,默认延时可能会比使用MySql时高,可以通过调整SDK轮询配置以及区块链打包时间进行实际调整。
当前默认开启simulate查询,即所有selcet查询语句均为simulate交易,实际使用时可根据需要进行配置调整;另外,如需要控制特定语句走simulate, 特定语句不走simulate,可以在应用端构造两个实例,两个实例使用不同的配置进行。