3. 快速开发

本章分别展示了使用java和c语言接口进行LightDB开发的过程。

3.1. java开发

本节展示了用java代码如何连接LightDB数据库,以及基本的执行流程。更多高级的执行功能参考 LightDB-JDBC 说明

3.1.1. JDBC

3.1.1.1. 引入驱动依赖

<!-- https://mvnrepository.com/artifact/io.github.hslightdb/ltjdbc -->
<dependency>
        <groupId>io.github.hslightdb</groupId>
        <artifactId>ltjdbc</artifactId>
        <version>42.2.24-23.1.0.1</version>
</dependency>

3.1.1.2. 加载连接驱动

Class.forName("org.postgresql.Driver");//加载LightDB连接驱动

3.1.1.3. 获取数据库连接

//连接之前需要准备数据库的url,用户名,密码
Connection newConnection = DriverManager.getConnection(Url,Username, Password);

//url的基本写法是:jdbcUrl=jdbc:postgresql://{host}:{port}/{database}?lightdbSyntaxCompatibleType=oracle
//{host}表示目标数据库IP
//{port}表示目标数据库端口
//{database}表示目标数据库名称

3.1.1.4. 执行sql和返回结果

//编写sql:如查询表的所有字段的内容select * from tableName
String sql="select * from tableName";
//调用获取到的数据库连接newConnection来调用prepareStatement方法创建PreparedStatement对象,同时该方法可以提高运行效率
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//调取preparedStatement对象的增删改查方法来得到结果,如查询executeQuery(),调用setString等来执行插入。调用executeUpdate()删除
//不用的方法返回不同的结果,细节参考`方法 <https://www.runoob.com/manual/jdk11api/java.sql/java/sql/PreparedStatement.html>`_
//以下是查询的返回结果,
ResultSet resultSet = preparedStatement.executeQuery();
//获取的resultSet的数据
while (resultSet.next()) {
        // 支持自动类型转换
        Double dou = resultSet.getObject(1, Double.class);
        Assert.assertEquals(Double.valueOf(1.1), dou);
}
//关闭连接
resultSet.close();
preparedStatement.close();
connection.close();

3.1.1.5. 例子

Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection("jdbc:postgresql://10.20.30.11:5432/fund60?lightdbSyntaxCompatibleType=oracle", "username", "password");
PreparedStatement preparedStatement = connection.prepareStatement("select to_number('1.1','9999.99')");
ResultSet resultSet = preparedStatement.executeQuery();

while (resultSet.next()) {
        Double dou = resultSet.getObject(1, Double.class);
        Assert.assertEquals(Double.valueOf(1.1), dou);
}

resultSet.close();
preparedStatement.close();
connection.close();

3.1.2. SpringBoot JdbcTemplate

3.1.2.1. 引入依赖

--引入spring-boot-starterjdbc依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
--引入LightDB的jdbc驱动
<dependency>
        <groupId>io.github.hslightdb</groupId>
        <artifactId>ltjdbc</artifactId>
        <version>42.2.24-23.1.0.1</version>
</dependency>

3.1.2.2. 配置数据源信息

在配置文件application.properties里面配置数据库的url,用户名,密码,驱动

spring.datasource.url=jdbc:postgresql://{host}:{port}/{database}
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver

3.1.2.3. 获取jdbcTemplate

//可通过自动装配来获取
@Autowired
JdbcTemplate jdbcTemplate;
//手动获取
JdbcTemplate jdbcTemplate=new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);

3.1.2.4. 执行和返回结果

调取JdbcTemplate的增删改查等方法来执行sql,并且返回结果。更多方法,参考 文档

//增加
String insertSql="insert into person(id,user_name,password) values(?,?,?)";
jdbcTemplate.update(insertSql,1,"tom","123456");
//查
String selectSql="select * from person where id =1";
Map<String, Object> map = jdbcTemplate.queryForMap(selectSql);
//删除
jdbcTemplate.update("DELETE FROM Student where id = ? ",id);

3.1.3. MyBatis

3.1.3.1. 引入依赖

<!--mybatis依赖-->
  <dependencies>
      <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
      <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.2</version>
      </dependency>

      <!--(mysql连接类)jdbc依赖,mybatis仍然需要用到jdbc,只是不需要我们手动配置jdbc-->
      <dependency>
          <groupId>io.github.hslightdb</groupId>
          <artifactId>ltjdbc</artifactId>
          <version>42.2.24-23.1.0.1</version>
       </dependency>
   </dependencies>

3.1.3.2. 配置文件修改参数

#在配置文件里面设置驱动
driver=org.postgresql.Driver
url=jdbc:postgresql://{host}:{port}/{database}
username=root
password=root

3.1.3.3. 配置连接

private static InputStream inputStream;
     //这个方法生成一个生产Sqlsession的工厂,即SqlSessionFactory
   public static SqlSessionFactory createfactory() {

       {
           try {
               inputStream = Resources.getResourceAsStream("mybatisconfig.xml");
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
       //通过把这个工厂return出来,以便后续通过这个工厂获得SqlSession对象
       return sqlSessionFactory;
   }
     //这个方法获得SqlSession对象,相当于JDBC中的statement
   public static SqlSession getsqlsession(){
       return createfactory().openSession();
   }

3.1.3.4. 创建实体类和执行sql的接口

public interface StudentDao {
    //查询全部用户
    List<Student> getstudentinfo();
    //根据id查询用户
    Student getstudentbyid(int id);
    List<Student> getstudentbyid2(HashMap<String, Object> map);
    int addUser(Student student);
    int updateStudent(Student student);
    int deleteStudent(int id);
}
public class Student {
    private int id;
    private String stname;
    private String sex;
    private String classs;
    private String telphone;

    public Student() {
    }

    public Student(int id, String stname, String sex, String classs, String telphone) {
        this.id = id;
        this.stname = stname;
        this.sex = sex;
        this.classs = classs;
        this.telphone = telphone;
    }
  }

3.1.3.5. 写sql语句

在接口对应的xml文件里面写需要的sql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--绑定接口-->
<mapper namespace="Dao.StudentDao">
     <!--查询-->
    <select id="getstudentinfo" resultType="pojo.Student">
       select  * from student
    </select>
     <!--增加-->
     <insert id="addUser"  parameterType="pojo.Student" >
        insert into student values(#{id},#{name},#{sex},#{classs},#{telphone})
    </insert>
     <!--修改-->
    <update id="updateStudent" parameterType="pojo.Student">
        update student set stname  =#{name},classs=#{classs}  where id =#{id};
    </update>
     <!--删除-->
    <delete id="deleteStudent" parameterType="int">
        delete from student where id =#{id}
    </delete>
</mapper>

3.1.3.6. 调用

 //通过GetSqlsession直接.getsqlsession这个静态方法获得SqlSession对象
 SqlSession sqlsession = GetSqlsession.getsqlsession();
//通过SqlSession的.getMapper方法,传入你接口的class获得接口,这里是java的反射机制
 StudentDao studentdao = sqlsession.getMapper(StudentDao.class);
 //通过接口类反射得到的接口对象studentdao直接调用其内部的方法
 List<Student> students = studentdao.getstudentinfo();
 //遍历输出这个List
 for (Student student : students) {
     System.out.println(student);
 }
 //切记!!!用完一定要把sqlsession对象关闭,不然会造成资源占用
 sqlsession.close();

3.1.4. JRESCloud3.X

是恒生自己开发的微服务框架,可通过该框架来配置数据库连接。这里举例结合Mybatis的使用方法。

3.1.4.1. 引入依赖

<!--引入JRESCloud3.X框架依赖-->
  <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>com.hundsun.jrescloud</groupId>
              <artifactId>jrescloud-dependencies</artifactId>
              <version>3.1.2</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      </dependencies>
  </dependencyManagement>
  <!--多数据源依赖-->
  <dependency>
      <groupId>com.hundsun.jrescloud.middleware</groupId>
      <artifactId>jrescloud-starter-mybatis</artifactId>
  </dependency>
  <!--引入LigjhtDB的JDBC驱动依赖-->
  <dependency>
            <groupId>io.github.hslightdb</groupId>
            <artifactId>ltjdbc</artifactId>
            <version>42.2.24-23.1.0.1</version>
    </dependency>
     <!--引入MysqlB的JDBC驱动依赖-->
    <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.46</version>
            </dependency>

3.1.4.2. 创建实体类

/**
* 多数据源注解@EnableCloudDataSource,开启多数据源功能
*/
@EnableCloudDataSource
@CloudApplication // 启动类注解,声明一个微服务应用
public class UnisqlMultiDataSourceApplication {

    public static void main(String[] args) {
        CloudBootstrap.run(UnisqlMultiDataSourceApplication.class, args);
    }
}

3.1.4.3. 设置配置文件

  1. 在配置文件src/main/resources/application.properties中配置多数据源。配置数据源之前要确保驱动已经引入依赖。

hs.druid.validationQuery=select 1

hs.datasource.default.driverClassName=驱动
hs.datasource.default.url=数据库连接地址
hs.datasource.default.username=用户名
hs.datasource.default.password=密码

#事例
#引入lightDB数据库的驱动
hs.datasource.default.driverClassName=org.postgresql.Driver
#数据库的url
hs.datasource.default.url=jdbc:postgresql://{host}:{port}/{database}
#数据库的用户名
hs.datasource.default.username=test1
#数据库的密码
hs.datasource.default.password=test1
#引入Mysql数据库的驱动
hs.datasource.mysql.driverClassName=com.mysql.jdbc.Driver
hs.datasource.mysql.url=jdbc:mysql://10.20.30.193:5757/test?useSSL=false&serverTimezone=UTC
hs.datasource.mysql.username=root
hs.datasource.mysql.password=123456
  1. 基于数据库厂商标识编写配置文件

mybatis.mapper-locations=classpath:mapper/**/*.xml

hs.druid.validationQuery=select 1

hs.datasource.mysql.driverClassName=com.mysql.jdbc.Driver
hs.datasource.mysql.url=jdbc:mysql://10.20.30.193:5757/test?useSSL=false&serverTimezone=UTC
hs.datasource.mysql.username=root
hs.datasource.mysql.password=123456


hs.datasource.default.driverClassName=com.hundsun.lightdb.unisql.proxy.Driver
hs.datasource.default.url=jdbc:unisql:postgresql://10.20.30.199:54333/testdb1?sourceDialect=oracle&targetDialect=postgresql
hs.datasource.default.username=test1
hs.datasource.default.password=test1

3.1.4.4. 编写接口实现

  1. 基于普通的Mybatis:使用注解@TargetDataSource指定当前服务类或服务方法所使用的数据源:

  public interface StudentDao {

      @TargetDataSource("mysql")
      List<Student> getstudentinfo();
      //根据id查询用户
      @TargetDataSource("mysql")
      Student getstudentbyid(int id);
      @TargetDataSource("default")
      List<Student> getstudentbyid2(HashMap<String, Object> map);
      @TargetDataSource("default")
      int addUser(Student student);
      @TargetDataSource("mysql")
      int updateStudent(Student student);
      @TargetDataSource("mysql")
      int deleteStudent(int id);
  }
public class Student {
      private int id;
      private String stname;
      private String sex;
      private String classs;
      private String telphone;

      public Student() {
      }

      public Student(int id, String stname, String sex, String classs, String telphone) {
          this.id = id;
          this.stname = stname;
          this.sex = sex;
          this.classs = classs;
          this.telphone = telphone;
      }
    }
  1. 基于数据库厂商标识(databaseIdProvider): 使用java config准备mybatis自定义配置类配置数据库厂商标识(databaseIdProvider):

@Configuration
public class MybatisConfig {
    @Bean
    public DatabaseIdProvider databaseIdProvider() {
        /**
        * 注意:基于jrescloud 3.x ,多数据源,配置文件application.properties中default数据源对应的数据库产品最终决定databaseId的取值(只作用一次)
        *  举例,default数据源为基于统一sql配置的数据库产品PostgreSQL且作为目标sql,但应用层使用的源sql为oracle,此时在properties中配置映射关系p.setProperty("PostgreSQL", "oracle"); 最终databaseId为oracle
        */
        DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties p = new Properties();
        p.setProperty("MySQL", "mysql");
        // 使用统一sql, 目标sql:postgresql 源sql:oracle
        p.setProperty("PostgreSQL", "oracle");
        databaseIdProvider.setProperties(p);
        return databaseIdProvider;
    }
}

3.1.4.5. 写sql语句

  1. 基于普通的Mybatis:在接口对应的xml文件里面写需要的sql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--绑定接口-->
<mapper namespace="Dao.StudentDao">
     <!--查询-->
    <select id="getstudentinfo" resultType="pojo.Student">
       select  * from student
    </select>
     <!--增加-->
     <insert id="addUser"  parameterType="pojo.Student" >
        insert into student values(#{id},#{name},#{sex},#{classs},#{telphone})
    </insert>
     <!--修改-->
    <update id="updateStudent" parameterType="pojo.Student">
        update student set stname  =#{name},classs=#{classs}  where id =#{id};
    </update>
     <!--删除-->
    <delete id="deleteStudent" parameterType="int">
        delete from student where id =#{id}
    </delete>
</mapper>
  1. 基于数据库厂商标识(databaseIdProvider)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.unisql.multi.db.mapper.TestMapper">

    <!--databaseId属性值指向源sql,这里是mysql-->
    <select id="queryForList" resultType="map" databaseId="mysql">
        select 1 from dual
    </select>

    <!--databaseId属性值指向源sql,这里是oracle-->
    <select id="queryForList" resultType="map" databaseId="oracle">
        select nation, listagg(city, ',') within GROUP (order by city1, city2 desc) from temp group by nation
    </select>
</mapper>

3.1.4.6. 调用

 //通过GetSqlsession直接.getsqlsession这个静态方法获得SqlSession对象
 SqlSession sqlsession = GetSqlsession.getsqlsession();
//通过SqlSession的.getMapper方法,传入你接口的class获得接口,这里是java的反射机制
 StudentDao studentdao = sqlsession.getMapper(StudentDao.class);
 //通过接口类反射得到的接口对象studentdao直接调用其内部的方法
 List<Student> students = studentdao.getstudentinfo();
 //遍历输出这个List
 for (Student student : students) {
     System.out.println(student);
 }
 //切记!!!用完一定要把sqlsession对象关闭,不然会造成资源占用
 sqlsession.close();

3.2. c开发

本节仅展示最基础的使用功能,更多C API接口可查看 官网 说明

准备测试:

--建表及生成测试数据
CREATE SCHEMA testlibpq3;
SET search_path = testlibpq3;
CREATE TABLE test1 (i int4, t text, b bytea);
INSERT INTO test1 values (1, 'joe''s place', '\000\001\002\003\004');
INSERT INTO test1 values (2, 'ho there', '\004\003\002\001\000');

--确保libpq已经安装
[lightdb@node101 testlibpq]$ whereis libpq
libpq: /usr/lib64/libpq.so /usr/include/libpq

使用c语言接口libpq开发第一个LightDB时,大致的执行步骤如下:

1. 包含头文件
#include "libpq-fe.h"

2. 连接数据库
conninfo = "host=127.0.0.1 port=5432 dbname = postgres user=lightdb password=!QAZ2wsx";
conn = PQconnectdb(conninfo);

3. 执行SQL语句
res = PQexec(conn, "SELECT * from test1 where name=''");
res = PQexec(conn, "delete from test1 where id=3");

4. 获取查询结果
PQgetvalue(res, 0, 0);

5. 清理结果
PQclear(res);

6. 关闭连接
PQfinish(conn);

下面使用一个样例来展示使用c语言接口libpq进行LightDB开发的过程

/*
 *           Test the C version of libpq, the LightDB frontend library.
 */
#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"

static void
exit_nicely(PGconn *conn)
{
     PQfinish(conn);
     exit(1);
}

int
main(int argc, char **argv)
{
     const char *conninfo;
     PGconn     *conn;
     PGresult   *res;
     int                     nFields;
     int                     i,
                             j;

     /*
      * 设置数据库连接串
      */
     conninfo = "host=127.0.0.1 port=5432 dbname = postgres user=lightdb password=!QAZ2wsx";

     /* 连接 */
     conn = PQconnectdb(conninfo);

     /* Check to see that the backend connection was successfully made */
     if (PQstatus(conn) != CONNECTION_OK)
     {
             fprintf(stderr, "Connection to database failed: %s",
                             PQerrorMessage(conn));
             exit_nicely(conn);
     }

     /* 设置search_path,只允许查询testlibpq3这个schema下的表 */
     res = PQexec(conn, "SET search_path = testlibpq3");
     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     {
             fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
             PQclear(res);
             exit_nicely(conn);
     }
     PQclear(res);

     /*
      * 执行select语句
      */
     res = PQexec(conn, "select * from test1");
     if (PQresultStatus(res) != PGRES_TUPLES_OK)
     {
             fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
             PQclear(res);
             exit_nicely(conn);
     }

     /* 输出列名 */
     nFields = PQnfields(res);
     for (i = 0; i < nFields; i++)
             printf("%-15s", PQfname(res, i));
     printf("\n");

     /* 输出具体行 */
     for (i = 0; i < PQntuples(res); i++)
     {
             for (j = 0; j < nFields; j++){
                     printf("%-15s", PQgetvalue(res, i, j));
             }
             printf("\n");
     }

     /* 清空查询结果 */
     PQclear(res);

     /* 关闭连接 */
     PQfinish(conn);

     return 0;
}

使用如下命令进行编译:

cc -o testlibpq3 testlibpq3.c -L /home/lightdb/stage/lightdb-x/lib -lpq -I/home/lightdb/stage/lightdb-x/include -g

执行编译出来的二进制文件testlibpq3,得到的结果如下:

[lightdb@node101 testlibpq]$ ./testlibpq3
i              t              b
1              joe's place    \x0001020304
2              ho there       \x0403020100