各种语言如何连接到 OceanBase
本篇文章想跟大家分享一下,各種主流開(kāi)發(fā)語(yǔ)言如何連接到 OceanBase 社區(qū)版數(shù)據(jù)庫(kù),進(jìn)行日常開(kāi)發(fā)。這個(gè)問(wèn)題也是社區(qū)群里面問(wèn)的比較多的一個(gè)問(wèn)題之一,希望通過(guò)本篇文章,能給各位參與開(kāi)發(fā)的小伙伴提供一些指導(dǎo)。
0. 前置條件
首先我們?cè)?OceanBase test 數(shù)據(jù)庫(kù)中創(chuàng)建一個(gè) t1 表,并向里面插入 2 條數(shù)據(jù),用作后面所有語(yǔ)言的測(cè)試基礎(chǔ)表:
1. Java 數(shù)據(jù)庫(kù)連接驅(qū)動(dòng)(JDBC)
首先上來(lái)肯定要說(shuō)一下 Java,說(shuō) Java 是第一大應(yīng)用開(kāi)發(fā)語(yǔ)言應(yīng)該不為過(guò)吧?OceanBase 社區(qū)版對(duì) MySQL 5.7 的兼容性最好,所以您可以使用 MySQL 5.7 的 JDBC 包(建議使用 mysql-connector-java-5.1.47 版本,MySQL 5.7 對(duì)應(yīng)的 JDBC 版本為 5.1.x),也可以使用 OceanBase 提供的自有 JDBC 包,下面我們分別用代碼演示一個(gè)簡(jiǎn)單的示例。
Java 數(shù)據(jù)庫(kù)連接(JDBC)是一種 API,它使 Java 能夠?qū)?SQL 語(yǔ)句發(fā)送到對(duì)象關(guān)系數(shù)據(jù)庫(kù),如 Oracle、MySQL 數(shù)據(jù)庫(kù)。JDBC 支持為 Java 暴露 SQL 數(shù)據(jù)類型,并快速訪問(wèn) SQL 數(shù)據(jù)。
1.1 MySQL JDBC 連接 Demo
我們首先從 https://downloads.mysql.com/archives/c-j/ 下載對(duì)應(yīng)的 5.1.47 的 jar 包,創(chuàng)建一個(gè)新的 Demo 項(xiàng)目,把剛才的 jar 包加載到類庫(kù)中,然后用最樸素的 Java 代碼執(zhí)行增刪改查操作,如下:
import java.sql.*; public class JavaDemo {public static void main(String[] args) throws ClassNotFoundException,SQLException {//1.加載驅(qū)動(dòng)Class.forName("com.mysql.jdbc.Driver");//固定寫法,加載驅(qū)動(dòng)//2.用戶信息和urlString url="jdbc:mysql://10.211.55.73:2883/test?useUnicode=true&characterEncoding=utf8&&useSSL=true";String username = "root";String password = "observer";//3.連接成功,連接數(shù)據(jù)庫(kù)對(duì)象 ConnectionConnection connection = DriverManager.getConnection(url,username,password);//4.執(zhí)行SQL對(duì)象 StatementStatement statement = connection.createStatement();//5.執(zhí)行SQL可能存在的結(jié)果,查看返回的結(jié)果System.out.println("-------------------當(dāng)前查詢到的數(shù)據(jù)如下-------------------");ResultSet resultSet = statement.executeQuery("SELECT * FROM t1");//返回的結(jié)果集,封裝了查詢出來(lái)的全部結(jié)果while(resultSet.next()) {System.out.println("id="+resultSet.getObject("id"));System.out.println("name="+resultSet.getObject("NAME"));}System.out.println("-------------------當(dāng)前數(shù)據(jù)庫(kù)的行數(shù)如下-------------------");ResultSet curCount = statement.executeQuery("select count(*) from t1");while(curCount.next()) {System.out.println("當(dāng)前數(shù)據(jù)庫(kù)有數(shù)據(jù) "+curCount.getInt(1)+" 行!");}System.out.println("-------------------向該數(shù)據(jù)庫(kù)中插入數(shù)據(jù)-------------------");String insertSql = "insert into t1 values(3,'c')";statement.execute(insertSql);//返回的結(jié)果System.out.println("-------------------插入數(shù)據(jù)后的行數(shù)如下-------------------");ResultSet afinCount = statement.executeQuery("select count(*) from t1");while(afinCount.next()) {System.out.println("當(dāng)前數(shù)據(jù)庫(kù)有數(shù)據(jù) "+afinCount.getInt(1)+" 行!");}System.out.println("-------------------嘗試更新插入進(jìn)去的數(shù)據(jù)-------------------");Integer updCount = statement.executeUpdate("update t1 set id=4 where name='c'");System.out.println("更新了 "+updCount+" 行數(shù)據(jù)!");System.out.println("-------------------嘗試進(jìn)行數(shù)據(jù)刪除-------------------");Boolean del = statement.execute("delete from t1 where name = 'c'");ResultSet afdelCount = statement.executeQuery("select count(*) from t1");while(afdelCount.next()) {System.out.println("當(dāng)前數(shù)據(jù)庫(kù)有數(shù)據(jù) "+afdelCount.getInt(1)+" 行!");}//6.釋放連接resultSet.close();statement.close();connection.close();} }執(zhí)行結(jié)果也一目了然,沒(méi)問(wèn)題:
1.2 OB 自研 JDBC 連接 Demo
OceanBase 官方提供了自研的 JDBC 包,名字叫做:oceanbase-client-1.1.10.jar。選用這個(gè)包的話,整體的操作方法跟 1.1 部分類似,主要區(qū)別為驅(qū)動(dòng)加載和 url 部分的定義:
//1.加載驅(qū)動(dòng)Class.forName("com.alipay.oceanbase.jdbc.Driver");//固定寫法,加載驅(qū)動(dòng)//2.用戶信息和urlString url="jdbc:oceanbase://10.211.55.73:2883/test";按照慣例來(lái)說(shuō),官方自研的 JDBC 驅(qū)動(dòng)在性能和語(yǔ)法兼容性上肯定會(huì)更好,當(dāng)然我沒(méi)有真正測(cè)過(guò)性能,大家可以自己測(cè)測(cè)試試。下面是一個(gè)完整 Demo 的增刪改查代碼:
import java.sql.*;public class JavaOBDemo {public static void main(String[] args) throws ClassNotFoundException,SQLException {//1.加載驅(qū)動(dòng)Class.forName("com.alipay.oceanbase.jdbc.Driver");//固定寫法,加載驅(qū)動(dòng)//2.用戶信息和urlString url="jdbc:oceanbase://10.211.55.73:2883/test";String username = "root";String password = "observer";//3.連接成功,連接數(shù)據(jù)庫(kù)對(duì)象 ConnectionConnection connection = DriverManager.getConnection(url,username,password);//4.執(zhí)行SQL對(duì)象 StatementStatement statement = connection.createStatement();//5.執(zhí)行SQL可能存在的結(jié)果,查看返回的結(jié)果System.out.println("-------------------當(dāng)前查詢到的數(shù)據(jù)如下-------------------");ResultSet resultSet = statement.executeQuery("SELECT * FROM t1");//返回的結(jié)果集,封裝了查詢出來(lái)的全部結(jié)果while(resultSet.next()) {System.out.println("id="+resultSet.getObject("id"));System.out.println("name="+resultSet.getObject("NAME"));}System.out.println("-------------------當(dāng)前數(shù)據(jù)庫(kù)的行數(shù)如下-------------------");ResultSet curCount = statement.executeQuery("select count(*) from t1");while(curCount.next()) {System.out.println("當(dāng)前數(shù)據(jù)庫(kù)有數(shù)據(jù) "+curCount.getInt(1)+" 行!");}System.out.println("-------------------向該數(shù)據(jù)庫(kù)中插入數(shù)據(jù)-------------------");String insertSql = "insert into t1 values(3,'c')";statement.execute(insertSql);//返回的結(jié)果System.out.println("-------------------插入數(shù)據(jù)后的行數(shù)如下-------------------");ResultSet afinCount = statement.executeQuery("select count(*) from t1");while(afinCount.next()) {System.out.println("當(dāng)前數(shù)據(jù)庫(kù)有數(shù)據(jù) "+afinCount.getInt(1)+" 行!");}System.out.println("-------------------嘗試更新插入進(jìn)去的數(shù)據(jù)-------------------");Integer updCount = statement.executeUpdate("update t1 set id=4 where name='c'");System.out.println("更新了 "+updCount+" 行數(shù)據(jù)!");System.out.println("-------------------嘗試進(jìn)行數(shù)據(jù)刪除-------------------");Boolean del = statement.execute("delete from t1 where name = 'c'");ResultSet afdelCount = statement.executeQuery("select count(*) from t1");while(afdelCount.next()) {System.out.println("當(dāng)前數(shù)據(jù)庫(kù)有數(shù)據(jù) "+afdelCount.getInt(1)+" 行!");}//6.釋放連接resultSet.close();statement.close();connection.close();} }有關(guān) OB 自研 JDBC 的參數(shù)調(diào)優(yōu),請(qǐng)參考官方文檔:https://open.oceanbase.com/docs/observer-cn/V3.1.4/10000000000450598
1.3 對(duì)常用框架的支持
這也是個(gè)經(jīng)常被問(wèn)到的問(wèn)題,我在社區(qū)群中不止一次看到有人問(wèn) OceanBase 對(duì)通用框架/連接池支持怎么樣?大家想想,OB 在阿里內(nèi)部及很多企業(yè)級(jí)客戶都有很深入的應(yīng)用了,對(duì)通用框架的支持已經(jīng)不會(huì)是一個(gè)大問(wèn)題了,簡(jiǎn)言之:支持的很不錯(cuò)。下面我列舉幾個(gè)官方給出的常用框架支持方式,供大家參考:
1.3.1 MyBatis 連接示例
MyBatis 作為一款應(yīng)用量排名靠前的框架,深受大家的喜愛(ài)。下面給出了一些常用的配置信息,供您參考:
配置依賴
<dependency><groupId>com.alipay.oceanbase</groupId><artifactId>oceanbase-client</artifactId><version>3.2.3</version> </dependency> <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.4</version> </dependency>mybatis-config.xml 配置文件
<?xml version="1.0" encoding="UTF8"?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.alipay.oceanbase.jdbc.Driver"/><property name="url" value="jdbc:oceanbase://10.100.xxx.xxx:18817/test?useUnicode=true&characterEncoding=utf-8&useServerPrepStmts=false&useCursorFetch=true"/><property name="username" value="admin@mysql"/><property name="password" value="admin"/></dataSource></environment></environments><!--注冊(cè)mapper(mapper.xml所在地址)--><mappers><mapper resource="com/test/UserMapper.xml"></mapper></mappers> </configuration>mapper.xml 配置文件
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace 是mapper接口,不能填錯(cuò)--> <mapper namespace="com.test.UserMapper"><select id="selectUser" resultType="com.test.User" fetchSize="40000">select * from user;</select><delete id="delete" >delete from user;</delete> </mapper>1.3.2 HiKariCP 連接池配置示例
HiKariCP 以代碼輕量且速度非常快著稱,以下信息展示了 OceanBase 與該框架的集成方法:
配置依賴 pom.xml
<dependency><groupId>com.alipay.oceanbase</groupId><artifactId>oceanbase-client</artifactId><version>3.2.3</version> </dependency> <dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>3.3.1</version> </dependency>配置文件 jdbc.properties
jdbcUrl=jdbc:oceanbase://10.100.xxx.xxx:18817/test?useSSL=false&useServerPrepStmts=true&serverTimezone=UTC username=admin@mysql password=admin dataSource.cachePrepStmts=true dataSource.prepStmtCacheSize=250 dataSource.prepStmtCacheSqlLimit=2048 dataSource.useServerPrepStmts=true dataSource.useLocalSessionState=true dataSource.rewriteBatchedStatements=true dataSource.cacheResultSetMetadata=true dataSource.cacheServerConfiguration=true dataSource.elideSetAutoCommits=true dataSource.maintainTimeStats=false示例代碼
@Testpublic void hikariTest() throws SQLException {HikariConfig config = new HikariConfig("/jdbc.properties");Connection conn = new HikariDataSource(config).getConnection();PreparedStatement drop_table_data_test = conn.prepareStatement("drop table data_test");Statement stmt = conn.createStatement();try {drop_table_data_test.execute();} catch (SQLException e) {}conn.prepareStatement("create table data_test(test1 int)").execute();for (int i = 0; i <= 10; i++) {stmt.executeUpdate("insert into data_test values("+i+")");}ResultSet rs = conn.prepareStatement("select * from data_test;").executeQuery();while (rs.next()){System.out.print(rs.getObject(1)+"\t");}System.out.println();System.out.println("------------------------");stmt.executeUpdate("update data_test set test1 = 100;");ResultSet rs1 = conn.prepareStatement("select * from data_test;").executeQuery();while (rs1.next()){System.out.print(rs1.getObject(1)+"\t");}System.out.println();System.out.println("------------------------");stmt.executeUpdate("delete from data_test");ResultSet rs2 = stmt.executeQuery("select * from data_test;");if (!rs2.next()){System.out.println("數(shù)據(jù)刪除成功");}stmt.close();drop_table_data_test.execute();drop_table_data_test.close();rs.close();conn.close();}1.3.3 SpringJDBC 連接示例
SpringJDBC 是老牌的持久層框架了,下面也來(lái)一個(gè)簡(jiǎn)單的 Demo:
配置依賴
<dependency><groupId>com.alipay.oceanbase</groupId><artifactId>oceanbase-client</artifactId><version>3.2.3</version> </dependency> <dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.0.9.RELEASE</version> </dependency>示例代碼
預(yù)加載靜態(tài)代碼塊(為方便測(cè)試,此處使用 druid 連接池):
static {Map<String, String> map = new HashMap<String, String>();map.put("url", "jdbc:oceanbase://10.100.xxx.xxx:18815/test");map.put("driverClassName", "com.alipay.oceanbase.jdbc.Driver");map.put("username", "admin@mysql");map.put("password", "admin");try {Class.forName(map.get("driverClassName"));jdbcTemplate = new JdbcTemplate(DruidDataSourceFactory.createDataSource(map));//防止異常語(yǔ)句,沒(méi)有這兩句,會(huì)出錯(cuò)jdbcTemplate.execute("set transaction_isolation = 'READ-COMMITTED';");jdbcTemplate.execute("set tx_isolation = 'READ-COMMITTED';");} catch (Exception e) {e.printStackTrace();} } @Testpublic void createByOrcTypeDate(){sql ="create table D_DPRECORD(DEV_ID VARCHAR2(50),"+"CAR_SPEED NUMBER(3),"+"CAP_DATE TIMESTAMP WITH LOCAL TIME ZONE," +"DEV_CHNID VARCHAR2(50) not null," +"TRSFMARK NUMBER(1) default 0," +"CREATE_TIME DATE default sysdate" +");";jdbcTemplate.execute(sql);} @Testpublic void addTest(){int i = 1;for (;i<=100;i++){sql = "insert into orc_type_test values ("+i+",'測(cè)試數(shù)據(jù)"+i+"');";jdbcTemplate.execute(sql);}} @Testpublic void selectTest(){sql = "select * from orc_type_test;";List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);for (Map<String,Object> m : maps){System.out.println(m);}} @Testpublic void rownumQueryTest() {sql = "select * from D_DPRECORD where rownum <=70 minus (select * from D_DPRECORD where rownum<60);";List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);for (Map<String, Object> m : maps) {System.out.println(m);}}1.3.4 其他連接池和框架
這里引入介紹了部分內(nèi)容,因?yàn)?Java 的連接池和框架太多了,所以為了保持篇幅不至于太冗長(zhǎng),不一一列舉了,如果大家對(duì)其他內(nèi)容感興趣,歡迎參考官方文檔的《設(shè)計(jì)規(guī)范和約束》–> 《數(shù)據(jù)庫(kù)設(shè)計(jì)最佳實(shí)踐》中的連接池和框架部分。
2. C/C++ 語(yǔ)言數(shù)據(jù)庫(kù)連接驅(qū)動(dòng)
OceanBase Connector/C 是一個(gè)基于 C/C++ 的 OceanBase 客戶端開(kāi)發(fā)組件,支持 C API Lib 庫(kù),我們通常也叫它 libobclient 。允許 C/C++ 程序以一種較為底層的方式訪問(wèn) OceanBase 分布式數(shù)據(jù)庫(kù)集群,以進(jìn)行數(shù)據(jù)庫(kù)連接、數(shù)據(jù)訪問(wèn)、錯(cuò)誤處理和 Prepared Statement 處理等操作。當(dāng)然您也可以使用 MySQL 官方的客戶端開(kāi)發(fā)組件:MySQL C API。但是優(yōu)先推薦采用 libobclient 進(jìn)行開(kāi)發(fā)。
2.1 安裝 libobclient
在使用該庫(kù)之前,我們需要先在對(duì)應(yīng)的服務(wù)器上安裝,例如執(zhí)行如下命令,從 OceanBase 遠(yuǎn)程倉(cāng)庫(kù)安裝,并復(fù)制一份到 lib64:
sudo yum install libobclient sudo cp -r /u01/obclient/lib/libobclnt.so.20 /usr/lib64/2.2 C++ 語(yǔ)言 Demo
完成了上面的基礎(chǔ)庫(kù)安裝后,下面我們還是通過(guò)一個(gè)例子來(lái)展示如何編寫 C++ 代碼:
#include <iostream> #include <cstdio> #include <cstdlib> #include "mysql.h"using namespace std;void process_result_set(MYSQL *mysql, MYSQL_RES *result) {printf("row nums: %d\n", mysql_num_rows(result)); //獲取行數(shù)int j = mysql_num_fields(result);MYSQL_ROW row = mysql_fetch_row(result);// 輸出每行結(jié)果if (row) {for (int i = 0; i < j; i++) {printf("%s \n", row[i]);}if (mysql_errno(mysql)) {printf("retrive faile: %s\n", mysql_error(mysql));return;}} } int main() {mysql_library_init(0, NULL, NULL);MYSQL *mysql = mysql_init(NULL);char host[] = "10.211.55.73"; char user[] = "root";char passwd[] = "observer";char db[] = "test"; //沒(méi)有數(shù)據(jù)庫(kù)可以選擇NULLunsigned int port = 2883;// 使用obclient連接ob的方式如下// obclient -h123.10.12.123 -P2883 -uroot@sys -pobserver/* 使用 CLIENT_MULTI_STATEMENTS 選項(xiàng)連接服務(wù)器 (必選)*/if (mysql_real_connect (mysql, host, user, passwd,NULL, port, NULL, CLIENT_MULTI_STATEMENTS) == NULL){printf("mysql_real_connect() failed\n");mysql_close(mysql);mysql_library_end();exit(1);}/*執(zhí)行多條語(yǔ)句 */int status = mysql_query(mysql,"show parameters like '%obconfig_url%';");if (status){printf("Could not execute statement(s), ret = %d\n", status);mysql_close(mysql);mysql_library_end();exit(0);}/* 處理每個(gè)語(yǔ)句的結(jié)果 */do {/* 當(dāng)前語(yǔ)句是否返回?cái)?shù)據(jù)? */MYSQL_RES* result = mysql_store_result(mysql);if (result){/* 是的; 則處理行并釋放結(jié)果集 */process_result_set(mysql, result); // 處理執(zhí)行成功的語(yǔ)句mysql_free_result(result);}else /* 沒(méi)有結(jié)果集或報(bào)錯(cuò) */{if (mysql_field_count(mysql) == 0){printf("%lld rows affected\n",mysql_affected_rows(mysql));}else /* 發(fā)生報(bào)錯(cuò) */{printf("Could not retrieve result set\n");break;}}/* 是否有更多結(jié)果? -1 = 否,>0 = 報(bào)錯(cuò),0 = 是(繼續(xù)循環(huán))*/if ((status = mysql_next_result(mysql)) > 0)printf("Could not execute statement\n");} while (status == 0);mysql_close(mysql);mysql_library_end();return 0; }編譯執(zhí)行返回的結(jié)果如下:
[chris@obd ~]$ g++ test.cpp -I /u01/obclient/include -L /u01/obclient/lib -lobclnt -o test [chris@obd ~]$ ./test row nums: 3 zone3 observer 10.211.55.76 2882 obconfig_url (null)URL for OBConfig service OBSERVER CLUSTER DEFAULT DYNAMIC_EFFECTIVE4. Python 連接數(shù)據(jù)庫(kù)指南
Python 在很多場(chǎng)景下被大量使用,大家所熟知的 OceanBase Deployer,即 obd 也是用 Python 開(kāi)發(fā)的。我們可以通過(guò)兩個(gè)不同的庫(kù)(Python 2 和 Python 3 有所區(qū)別)連接到 OceanBase。下面分別展開(kāi):
4.1 Python 3 連接方式
官方推薦在 Python 3 環(huán)境下,選用 PyMySQL 庫(kù)來(lái)連接 OceanBase,首先如果您本地沒(méi)有下載該庫(kù),需要先執(zhí)行 pip 進(jìn)行安裝:
python3 -m pip install PyMySQL安裝完成后,可以通過(guò)如下代碼進(jìn)行數(shù)據(jù)庫(kù)訪問(wèn),主要就是注意 import 庫(kù)的導(dǎo)入:
import pymysqlconn = pymysql.connect(host="10.211.55.73", port=2883,user="root", passwd="observer", db="test")try:with conn.cursor() as cur:cur.execute('SELECT * FROM t1')rows = cur.fetchall()for row in rows:print(f'{row[0]} {row[1]}')finally:conn.close()執(zhí)行如上代碼返回結(jié)果也正常:
4.2 Python 2 連接方式
MySQL-python 是 Python2.X 版本中用于連接 MySQL 服務(wù)器的一個(gè)庫(kù)。官方推薦采用該庫(kù)在 Python 2 上連接 OceanBase。
首先也是需要手工安裝該庫(kù):
sudo pip install MySQL-python示例代碼及返回結(jié)果如下:
import MySQLdbconn= MySQLdb.connect(host='10.211.55.73',port = 2883,user='root',passwd='observer',db ='test' )try:cur = conn.cursor()cur.execute('SELECT * from t1')ans = cur.fetchall()print(ans)finally:conn.close() [chris@obd ~]$ python test.py ((1L, 'a'), (2L, 'b'))5. Golang 驅(qū)動(dòng)鏈接 OceanBase Demo
在 Golang 開(kāi)發(fā)環(huán)境下,推薦采用 Go-SQL-Driver/MySQL 來(lái)進(jìn)行連接。這要求 Go 的版本要在 1.13 之上。
5.1 下載對(duì)應(yīng)的庫(kù)
go get -u github.com/go-sql-driver/mysql5.2 Demo 演示
package mainimport ("database/sql""fmt""log"_ "github.com/go-sql-driver/mysql" )type TS struct {Id intName string }func select_all() {conn := "root:obsever@tcp(10.211.55.73:2883)/test"db, err := sql.Open("mysql", conn)if err != nil {log.Fatal(err)}defer db.Close()if err != nil {log.Fatal(err)}res, err := db.Query("SELECT * FROM t1")if err != nil {log.Fatal(err)}defer res.Close()if err != nil {log.Fatal(err)}for res.Next() {var t TSerr := res.Scan(&t.Id, &t.Name)if err != nil {log.Fatal(err)}fmt.Printf("%v\n", t)} }func main() {select_all() }執(zhí)行結(jié)果截圖如下,此處注意環(huán)境變量 GO111MODULE的設(shè)置,否則會(huì)去查找 mod 文件并導(dǎo)致無(wú)法執(zhí)行:
總結(jié)
以上是生活随笔為你收集整理的各种语言如何连接到 OceanBase的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 数组输出c语言getchar,C语言入门
- 下一篇: python下拉框二级联动_Excel数