Merge branch 'develop' into feature/slguan
This commit is contained in:
commit
02e39aab35
|
@ -188,58 +188,107 @@ TDengine提供时间驱动的实时流式计算API。可以每隔一指定的时
|
|||
|
||||
## Java Connector
|
||||
|
||||
### JDBC接口
|
||||
TDengine 为了方便 Java 应用使用,提供了遵循 JDBC 标准(3.0)API 规范的 `taos-jdbcdriver` 实现。目前可以通过 [Sonatype Repository][1] 搜索并下载。
|
||||
|
||||
如果用户使用Java开发企业级应用,可选用 TDengine 提供的 JDBC Driver 来调用服务。TDengine 提供的 JDBC Driver 是标准 JDBC 规范的子集,遵循 JDBC 标准 (3.0)API 规范,支持现有的各种 Java 开发框架。目前 TDengine 的 JDBC driver 已经发布到 Sonatype Maven Repository。因此用户开发时,需要在 pom.xml 文件中进行如下配置:
|
||||
由于 TDengine 是使用 c 语言开发的,使用 taos-jdbcdriver 驱动包时需要依赖系统对应的本地函数库。
|
||||
|
||||
* libtaos.so
|
||||
在 linux 系统中成功安装 TDengine 后,依赖的本地函数库 libtaos.so 文件会被自动拷贝至 /usr/lib/libtaos.so,该目录包含在 Linux 自动扫描路径上,无需单独指定。
|
||||
|
||||
* taos.dll
|
||||
在 windows 系统中安装完客户端之后,驱动包依赖的 taos.dll 文件会自动拷贝到系统默认搜索路径 C:/Windows/System32 下,同样无需要单独指定。
|
||||
|
||||
> 注意:在 windows 环境开发时需要安装 TDengine 对应的 windows 版本客户端,由于目前没有提供 Linux 环境单独的客户端,需要安装 TDengine 才能使用。
|
||||
|
||||
TDengine 的 JDBC 驱动实现尽可能的与关系型数据库驱动保持一致,但时序空间数据库与关系对象型数据库服务的对象和技术特征的差异导致 taos-jdbcdriver 并未完全实现 JDBC 标准规范。在使用时需要注意以下几点:
|
||||
|
||||
* TDengine 不提供针对单条数据记录的删除和修改的操作,驱动中也没有支持相关方法。
|
||||
* 由于不支持删除和修改,所以也不支持事务操作。
|
||||
* 目前不支持表间的 union 操作。
|
||||
* 目前不支持嵌套查询(nested query),`对每个 Connection 的实例,至多只能有一个打开的 ResultSet 实例;如果在 ResultSet还没关闭的情况下执行了新的查询,TSDBJDBCDriver 则会自动关闭上一个 ResultSet`。
|
||||
|
||||
|
||||
## TAOS-JDBCDriver 版本以及支持的 TDengine 版本和 JDK 版本
|
||||
|
||||
| taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 |
|
||||
| --- | --- | --- |
|
||||
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.1 | 1.6.1.x 及以上 | 1.8.x |
|
||||
|
||||
## TDengine DataType 和 Java DataType
|
||||
|
||||
TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对应类型转换如下:
|
||||
|
||||
| TDengine DataType | Java DataType |
|
||||
| --- | --- |
|
||||
| TIMESTAMP | java.sql.Timestamp |
|
||||
| INT | java.lang.Integer |
|
||||
| BIGINT | java.lang.Long |
|
||||
| FLOAT | java.lang.Float |
|
||||
| DOUBLE | java.lang.Double |
|
||||
| SMALLINT, TINYINT |java.lang.Short |
|
||||
| BOOL | java.lang.Boolean |
|
||||
| BINARY, NCHAR | java.lang.String |
|
||||
|
||||
## 如何获取 TAOS-JDBCDriver
|
||||
|
||||
### maven 仓库
|
||||
|
||||
目前 taos-jdbcdriver 已经发布到 [Sonatype Repository][1] 仓库,且各大仓库都已同步。
|
||||
* [sonatype][8]
|
||||
* [mvnrepository][9]
|
||||
* [maven.aliyun][10]
|
||||
|
||||
maven 项目中使用如下 pom.xml 配置即可:
|
||||
|
||||
```xml
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>oss-sonatype</id>
|
||||
<name>oss-sonatype</name>
|
||||
<url>https://oss.sonatype.org/content/groups/public</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>taos-jdbcdriver</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
```
|
||||
|
||||
TDengine 的驱动程序包的在不同操作系统上依赖不同的本地函数库(均由C语言编写)。Linux系统上,依赖一个名为`libtaos.so` 的本地库,.so即"Shared Object"缩写。成功安装TDengine后,`libtaos.so` 文件会被自动拷贝至`/usr/local/lib/taos`目录下,该目录也包含在Linux上自动扫描路径上。Windows系统上,JDBC驱动程序依赖于一个名为`taos.dll` 的本地库,.dll是动态链接库"Dynamic Link Library"的缩写。Windows上成功安装客户端后,JDBC驱动程序包默认位于`C:/TDengine/driver/JDBC/`目录下;其依赖的动态链接库`taos.dll`文件位于`C:/TDengine/driver/C`目录下,`taos.dll` 会被自动拷贝至系统默认搜索路径`C:/Windows/System32`下。
|
||||
### 源码编译打包
|
||||
|
||||
TDengine的JDBC Driver遵循标准JDBC规范,开发人员可以参考Oracle官方的JDBC相关文档来找到具体的接口和方法的定义与用法。TDengine的JDBC驱动在连接配置和支持的方法上与传统数据库驱动稍有不同。
|
||||
下载 [TDengine][3] 源码之后,进入 taos-jdbcdriver 源码目录 `src/connector/jdbc` 执行 `mvn clean package` 即可生成相应 jar 包。
|
||||
|
||||
TDengine的JDBC URL规范格式为:
|
||||
|
||||
`jdbc:TSDB://{host_ip}:{port}/{database_name}?[user={user}|&password={password}|&charset={charset}|&cfgdir={config_dir}|&locale={locale}|&timezone={timezone}]`
|
||||
## 使用说明
|
||||
|
||||
其中,`{}`中的内容必须,`[]`中为可选。配置参数说明如下:
|
||||
|
||||
- user:登陆TDengine所用用户名;默认值root
|
||||
- password:用户登陆密码;默认值taosdata
|
||||
- charset:客户端使用的字符集;默认值为系统字符集
|
||||
- cfgdir:客户端配置文件目录路径;Linux OS上默认值`/etc/taos` ,Windows OS上默认值 `C:/TDengine/cfg`
|
||||
- locale:客户端语言环境;默认值系统当前locale
|
||||
- timezone:客户端使用的时区;默认值为系统当前时区
|
||||
|
||||
以上所有参数均可在调用java.sql.DriverManager类创建连接时指定,示例如下:
|
||||
### 获取连接
|
||||
|
||||
如下所示配置即可获取 TDengine Connection:
|
||||
```java
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.Properties;
|
||||
import com.taosdata.jdbc.TSDBDriver;
|
||||
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||
String jdbcUrl = "jdbc:TAOS://127.0.0.1:6030/log?user=root&password=taosdata";
|
||||
Connection conn = DriverManager.getConnection(jdbcUrl);
|
||||
```
|
||||
> 端口 6030 为默认连接端口,JDBC URL 中的 log 为系统本身的监控数据库。
|
||||
|
||||
TDengine 的 JDBC URL 规范格式为:
|
||||
`jdbc:TSDB://{host_ip}:{port}/[database_name]?[user={user}|&password={password}|&charset={charset}|&cfgdir={config_dir}|&locale={locale}|&timezone={timezone}]`
|
||||
|
||||
其中,`{}` 中的内容必须,`[]` 中为可选。配置参数说明如下:
|
||||
|
||||
* user:登录 TDengine 用户名,默认值 root。
|
||||
* password:用户登录密码,默认值 taosdata。
|
||||
* charset:客户端使用的字符集,默认值为系统字符集。
|
||||
* cfgdir:客户端配置文件目录路径,Linux OS 上默认值 /etc/taos ,Windows OS 上默认值 C:/TDengine/cfg。
|
||||
* locale:客户端语言环境,默认值系统当前 locale。
|
||||
* timezone:客户端使用的时区,默认值为系统当前时区。
|
||||
|
||||
以上参数可以在 3 处配置,`优先级由高到低`分别如下:
|
||||
1. JDBC URL 参数
|
||||
如上所述,可以在 JDBC URL 的参数中指定。
|
||||
2. java.sql.DriverManager.getConnection(String jdbcUrl, Properties connProps)
|
||||
```java
|
||||
public Connection getConn() throws Exception{
|
||||
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||
String jdbcUrl = "jdbc:TAOS://127.0.0.1:0/db?user=root&password=taosdata";
|
||||
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||
String jdbcUrl = "jdbc:TAOS://127.0.0.1:0/log?user=root&password=taosdata";
|
||||
Properties connProps = new Properties();
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_USER, "root");
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, "taosdata");
|
||||
|
@ -252,16 +301,203 @@ public Connection getConn() throws Exception{
|
|||
}
|
||||
```
|
||||
|
||||
这些配置参数中除了cfgdir外,均可在客户端配置文件taos.cfg中进行配置。调用java.sql.DriverManager时声明的配置参数优先级最高,JDBC URL的优先级次之,配置文件的优先级最低。例如charset同时在配置文件taos.cfg中配置,也在JDBC URL中配置,则使用JDBC URL中的配置值。
|
||||
3. 客户端配置文件 taos.cfg
|
||||
|
||||
此外,尽管TDengine的JDBC驱动实现尽可能的与关系型数据库驱动保持一致,但时序空间数据库与关系对象型数据库服务的对象和技术特征的差异导致TDengine的Java API并不能与标准完全相同。对于有大量关系型数据库开发经验而初次接触TDengine的开发者来说,有以下一些值的注意的地方:
|
||||
linux 系统默认配置文件为 /var/lib/taos/taos.cfg,windows 系统默认配置文件路径为 C:\TDengine\cfg\taos.cfg。
|
||||
```properties
|
||||
# client default username
|
||||
# defaultUser root
|
||||
|
||||
* TDengine不提供针对单条数据记录的删除和修改的操作,驱动中也没有支持相关方法
|
||||
* 目前TDengine不支持表间的join或union操作,因此也缺乏对该部分API的支持
|
||||
* TDengine支持批量写入,但是支持停留在SQL语句级别,而不是API级别,也就是说用户需要通过写特殊的SQL语句来实现批量
|
||||
* 目前TDengine不支持嵌套查询(nested query),对每个Connection的实例,至多只能有一个打开的ResultSet实例;如果在ResultSet还没关闭的情况下执行了新的查询,TSDBJDBCDriver则会自动关闭上一个ResultSet
|
||||
# client default password
|
||||
# defaultPass taosdata
|
||||
|
||||
对于TDengine操作的报错信息,用户可使用JDBCDriver包里提供的枚举类TSDBError.java来获取error message和error code的列表。对于更多的具体操作的相关代码,请参考TDengine提供的使用示范项目`JDBCDemo`。
|
||||
# default system charset
|
||||
# charset UTF-8
|
||||
|
||||
# system locale
|
||||
# locale en_US.UTF-8
|
||||
```
|
||||
> 更多详细配置请参考[客户端配置][13]
|
||||
|
||||
### 创建数据库和表
|
||||
|
||||
```java
|
||||
Statement stmt = conn.createStatement();
|
||||
|
||||
// create database
|
||||
stmt.executeUpdate("create database if not exists db");
|
||||
|
||||
// use database
|
||||
stmt.executeUpdate("use db");
|
||||
|
||||
// create table
|
||||
stmt.executeUpdate("create table if not exists tb (ts timestamp, temperature int, humidity float)");
|
||||
```
|
||||
> 注意:如果不使用 `use db` 指定数据库,则后续对表的操作都需要增加数据库名称作为前缀,如 db.tb。
|
||||
|
||||
### 插入数据
|
||||
|
||||
```java
|
||||
// insert data
|
||||
int affectedRows = stmt.executeUpdate("insert into tb values(now, 23, 10.3) (now + 1s, 20, 9.3)");
|
||||
|
||||
System.out.println("insert " + affectedRows + " rows.");
|
||||
```
|
||||
> now 为系统内部函数,默认为服务器当前时间。
|
||||
> `now + 1s` 代表服务器当前时间往后加 1 秒,数字后面代表时间单位:a(毫秒), s(秒), m(分), h(小时), d(天),w(周), n(月), y(年)。
|
||||
|
||||
### 查询数据
|
||||
|
||||
```java
|
||||
// query data
|
||||
ResultSet resultSet = stmt.executeQuery("select * from tb");
|
||||
|
||||
Timestamp ts = null;
|
||||
int temperature = 0;
|
||||
float humidity = 0;
|
||||
while(resultSet.next()){
|
||||
|
||||
ts = resultSet.getTimestamp(1);
|
||||
temperature = resultSet.getInt(2);
|
||||
humidity = resultSet.getFloat("humidity");
|
||||
|
||||
System.out.printf("%s, %d, %s\n", ts, temperature, humidity);
|
||||
}
|
||||
```
|
||||
> 查询和操作关系型数据库一致,使用下标获取返回字段内容时从 1 开始,建议使用字段名称获取。
|
||||
|
||||
|
||||
### 关闭资源
|
||||
|
||||
```java
|
||||
resultSet.close();
|
||||
stmt.close();
|
||||
conn.close();
|
||||
```
|
||||
> `注意务必要将 connection 进行关闭`,否则会出现连接泄露。
|
||||
## 与连接池使用
|
||||
|
||||
**HikariCP**
|
||||
|
||||
* 引入相应 HikariCP maven 依赖:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
* 使用示例如下:
|
||||
```java
|
||||
public static void main(String[] args) throws SQLException {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl("jdbc:TAOS://127.0.0.1:6030/log");
|
||||
config.setUsername("root");
|
||||
config.setPassword("taosdata");
|
||||
|
||||
config.setMinimumIdle(3); //minimum number of idle connection
|
||||
config.setMaximumPoolSize(10); //maximum number of connection in the pool
|
||||
config.setConnectionTimeout(10000); //maximum wait milliseconds for get connection from pool
|
||||
config.setIdleTimeout(60000); // max idle time for recycle idle connection
|
||||
config.setConnectionTestQuery("describe log.dn"); //validation query
|
||||
config.setValidationTimeout(3000); //validation query timeout
|
||||
|
||||
HikariDataSource ds = new HikariDataSource(config); //create datasource
|
||||
|
||||
Connection connection = ds.getConnection(); // get connection
|
||||
Statement statement = connection.createStatement(); // get statement
|
||||
|
||||
//query or insert
|
||||
// ...
|
||||
|
||||
connection.close(); // put back to conneciton pool
|
||||
}
|
||||
```
|
||||
> 通过 HikariDataSource.getConnection() 获取连接后,使用完成后需要调用 close() 方法,实际上它并不会关闭连接,只是放回连接池中。
|
||||
> 更多 HikariCP 使用问题请查看[官方说明][5]
|
||||
|
||||
**Druid**
|
||||
|
||||
* 引入相应 Druid maven 依赖:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.1.20</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
* 使用示例如下:
|
||||
```java
|
||||
public static void main(String[] args) throws Exception {
|
||||
Properties properties = new Properties();
|
||||
properties.put("driverClassName","com.taosdata.jdbc.TSDBDriver");
|
||||
properties.put("url","jdbc:TAOS://127.0.0.1:6030/log");
|
||||
properties.put("username","root");
|
||||
properties.put("password","taosdata");
|
||||
|
||||
properties.put("maxActive","10"); //maximum number of connection in the pool
|
||||
properties.put("initialSize","3");//initial number of connection
|
||||
properties.put("maxWait","10000");//maximum wait milliseconds for get connection from pool
|
||||
properties.put("minIdle","3");//minimum number of connection in the pool
|
||||
|
||||
properties.put("timeBetweenEvictionRunsMillis","3000");// the interval milliseconds to test connection
|
||||
|
||||
properties.put("minEvictableIdleTimeMillis","60000");//the minimum milliseconds to keep idle
|
||||
properties.put("maxEvictableIdleTimeMillis","90000");//the maximum milliseconds to keep idle
|
||||
|
||||
properties.put("validationQuery","describe log.dn"); //validation query
|
||||
properties.put("testWhileIdle","true"); // test connection while idle
|
||||
properties.put("testOnBorrow","false"); // don't need while testWhileIdle is true
|
||||
properties.put("testOnReturn","false"); // don't need while testWhileIdle is true
|
||||
|
||||
//create druid datasource
|
||||
DataSource ds = DruidDataSourceFactory.createDataSource(properties);
|
||||
Connection connection = ds.getConnection(); // get connection
|
||||
Statement statement = connection.createStatement(); // get statement
|
||||
|
||||
//query or insert
|
||||
// ...
|
||||
|
||||
connection.close(); // put back to conneciton pool
|
||||
}
|
||||
```
|
||||
> 更多 druid 使用问题请查看[官方说明][6]
|
||||
|
||||
**注意事项**
|
||||
* TDengine `v1.6.4.1` 版本开始提供了一个专门用于心跳检测的函数 `select server_status()`,所以在使用连接池时推荐使用 `select server_status()` 进行 Validation Query。
|
||||
|
||||
如下所示,`select server_status()` 执行成功会返回 `1`。
|
||||
```shell
|
||||
taos> select server_status();
|
||||
server_status()|
|
||||
================
|
||||
1 |
|
||||
Query OK, 1 row(s) in set (0.000141s)
|
||||
```
|
||||
|
||||
## 与框架使用
|
||||
|
||||
* Spring JdbcTemplate 中使用 taos-jdbcdriver,可参考 [SpringJdbcTemplate][11]
|
||||
* Springboot + Mybatis 中使用,可参考 [springbootdemo][12]
|
||||
|
||||
## 常见问题
|
||||
|
||||
* java.lang.UnsatisfiedLinkError: no taos in java.library.path
|
||||
|
||||
**原因**:程序没有找到依赖的本地函数库 taos。
|
||||
|
||||
**解决方法**:windows 下可以将 C:\TDengine\driver\taos.dll 拷贝到 C:\Windows\System32\ 目录下,linux 下将建立如下软链 ` ln -s /usr/local/taos/driver/libtaos.so.x.x.x.x /usr/lib/libtaos.so` 即可。
|
||||
|
||||
* java.lang.UnsatisfiedLinkError: taos.dll Can't load AMD 64 bit on a IA 32-bit platform
|
||||
|
||||
**原因**:目前 TDengine 只支持 64 位 JDK。
|
||||
|
||||
**解决方法**:重新安装 64 位 JDK。
|
||||
|
||||
* 其它问题请参考 [Issues][7]
|
||||
|
||||
## Python Connector
|
||||
|
||||
|
@ -811,30 +1047,30 @@ https://gitee.com/maikebing/Maikebing.EntityFrameworkCore.Taos
|
|||
|
||||
```
|
||||
├── cfg
|
||||
│ └── taos.cfg
|
||||
├───└── taos.cfg
|
||||
├── connector
|
||||
│ ├── go
|
||||
│ ├── grafana
|
||||
│ ├── jdbc
|
||||
│ └── python
|
||||
├───├── go
|
||||
├───├── grafana
|
||||
├───├── jdbc
|
||||
├───└── python
|
||||
├── driver
|
||||
│ ├── taos.dll
|
||||
│ ├── taos.exp
|
||||
│ └── taos.lib
|
||||
├───├── taos.dll
|
||||
├───├── taos.exp
|
||||
├───└── taos.lib
|
||||
├── examples
|
||||
│ ├── bash
|
||||
│ ├── c
|
||||
│ ├── C#
|
||||
│ ├── go
|
||||
│ ├── JDBC
|
||||
│ ├── lua
|
||||
│ ├── matlab
|
||||
│ ├── nodejs
|
||||
│ ├── python
|
||||
│ ├── R
|
||||
│ └── rust
|
||||
├───├── bash
|
||||
├───├── c
|
||||
├───├── C#
|
||||
├───├── go
|
||||
├───├── JDBC
|
||||
├───├── lua
|
||||
├───├── matlab
|
||||
├───├── nodejs
|
||||
├───├── python
|
||||
├───├── R
|
||||
├───└── rust
|
||||
├── include
|
||||
│ └── taos.h
|
||||
├───└── taos.h
|
||||
└── taos.exe
|
||||
```
|
||||
|
||||
|
@ -879,3 +1115,16 @@ TDengine在Window系统上提供的API与Linux系统是相同的, 应用程序
|
|||
+ 将Windows开发包(taos.dll)放置到system32目录下。
|
||||
|
||||
|
||||
[1]: https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[2]: https://mvnrepository.com/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[3]: https://github.com/taosdata/TDengine
|
||||
[4]: https://www.taosdata.com/blog/2019/12/03/jdbcdriver%e6%89%be%e4%b8%8d%e5%88%b0%e5%8a%a8%e6%80%81%e9%93%be%e6%8e%a5%e5%ba%93/
|
||||
[5]: https://github.com/brettwooldridge/HikariCP
|
||||
[6]: https://github.com/alibaba/druid
|
||||
[7]: https://github.com/taosdata/TDengine/issues
|
||||
[8]: https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[9]: https://mvnrepository.com/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[10]: https://maven.aliyun.com/mvn/search
|
||||
[11]: https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/SpringJdbcTemplate
|
||||
[12]: https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/springbootdemo
|
||||
[13]: https://www.taosdata.com/cn/documentation/administrator/#%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE
|
||||
|
|
|
@ -313,9 +313,9 @@ vercomp () {
|
|||
|
||||
function is_version_compatible() {
|
||||
|
||||
curr_version=$(${bin_dir}/taosd -V | head -1 | cut -d ' ' -f 2)
|
||||
curr_version=$(${bin_dir}/taosd -V | head -1 | cut -d ' ' -f 3)
|
||||
|
||||
min_compatible_version=$(${script_dir}/bin/taosd -V | head -1 | cut -d ' ' -f 4)
|
||||
min_compatible_version=$(${script_dir}/bin/taosd -V | head -1 | cut -d ' ' -f 5)
|
||||
|
||||
vercomp $curr_version $min_compatible_version
|
||||
case $? in
|
||||
|
|
|
@ -108,12 +108,12 @@ static tSQLSyntaxNode *tSQLSyntaxNodeCreate(SSchema *pSchema, int32_t numOfCols,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int32_t i = 0;
|
||||
size_t nodeSize = sizeof(tSQLSyntaxNode);
|
||||
tSQLSyntaxNode *pNode = NULL;
|
||||
|
||||
if (pToken->type == TK_ID || pToken->type == TK_TBNAME) {
|
||||
if (pToken->type == TK_ID) {
|
||||
int32_t i = 0;
|
||||
do {
|
||||
size_t len = strlen(pSchema[i].name);
|
||||
if (strncmp(pToken->z, pSchema[i].name, pToken->n) == 0 && pToken->n == len) break;
|
||||
|
@ -268,8 +268,8 @@ static tSQLSyntaxNode *createSyntaxTree(SSchema *pSchema, int32_t numOfCols, cha
|
|||
}
|
||||
|
||||
// get the operator of expr
|
||||
uint8_t optr = getBinaryExprOptr(&t0);
|
||||
if (optr <= 0) {
|
||||
uint8_t optr = getBinaryExprOptr(&t0);
|
||||
if (optr == 0) {
|
||||
pError("not support binary operator:%d", t0.type);
|
||||
tSQLSyntaxNodeDestroy(pLeft, NULL);
|
||||
return NULL;
|
||||
|
@ -323,10 +323,11 @@ static tSQLSyntaxNode *createSyntaxTree(SSchema *pSchema, int32_t numOfCols, cha
|
|||
pn->colId = -1;
|
||||
return pn;
|
||||
} else {
|
||||
uint8_t localOptr = getBinaryExprOptr(&t0);
|
||||
if (localOptr <= 0) {
|
||||
uint8_t localOptr = getBinaryExprOptr(&t0);
|
||||
if (localOptr == 0) {
|
||||
pError("not support binary operator:%d", t0.type);
|
||||
return NULL;
|
||||
free(pBinExpr)
|
||||
}
|
||||
|
||||
return parseRemainStr(str, pBinExpr, pSchema, localOptr, numOfCols, i);
|
||||
|
@ -418,16 +419,17 @@ void tSQLBinaryExprToString(tSQLBinaryExpr *pExpr, char *dst, int32_t *len) {
|
|||
if (pExpr == NULL) {
|
||||
*dst = 0;
|
||||
*len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t lhs = tSQLBinaryExprToStringImpl(pExpr->pLeft, dst, pExpr->pLeft->nodeType);
|
||||
int32_t lhs = tSQLBinaryExprToStringImpl(pExpr->pLeft, dst, pExpr->pLeft->nodeType);
|
||||
dst += lhs;
|
||||
*len = lhs;
|
||||
|
||||
char *start = tSQLOptrToString(pExpr->nSQLBinaryOptr, dst);
|
||||
char *start = tSQLOptrToString(pExpr->nSQLBinaryOptr, dst);
|
||||
*len += (start - dst);
|
||||
|
||||
*len += tSQLBinaryExprToStringImpl(pExpr->pRight, start, pExpr->pRight->nodeType);
|
||||
*len += tSQLBinaryExprToStringImpl(pExpr->pRight, start, pExpr->pRight->nodeType);
|
||||
}
|
||||
|
||||
static void UNUSED_FUNC destroySyntaxTree(tSQLSyntaxNode *pNode) { tSQLSyntaxNodeDestroy(pNode, NULL); }
|
||||
|
@ -650,7 +652,8 @@ void tSQLListTraverseOnResult(struct tSQLBinaryExpr *pExpr, bool (*fp)(tSkipList
|
|||
// brutal force search
|
||||
int64_t num = pResult->num;
|
||||
for (int32_t i = 0, j = 0; i < pResult->num; ++i) {
|
||||
if (fp == NULL || (fp != NULL && fp(pResult->pRes[i], pExpr->info) == true)) {
|
||||
//if (fp == NULL || (fp != NULL && fp(pResult->pRes[i], pExpr->info) == true)) {
|
||||
if (fp == NULL || (fp(pResult->pRes[i], pExpr->info) == true)) {
|
||||
pResult->pRes[j++] = pResult->pRes[i];
|
||||
} else {
|
||||
num--;
|
||||
|
|
|
@ -157,7 +157,6 @@ static void tscProcessAsyncRetrieveImpl(void *param, TAOS_RES *tres, int numOfRo
|
|||
SSqlObj *pSql = (SSqlObj *)tres;
|
||||
if (pSql == NULL) { // error
|
||||
tscError("sql object is NULL");
|
||||
tscQueueAsyncError(pSql->fetchFp, param);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ static int32_t tsCheckTimestamp(STableDataBlocks *pDataBlocks, const char *start
|
|||
}
|
||||
|
||||
int tsParseOneRowData(char **str, STableDataBlocks *pDataBlocks, SSchema schema[], SParsedDataColInfo *spd, char *error,
|
||||
int16_t timePrec) {
|
||||
int16_t timePrec, int32_t *code, char* tmpTokenBuf) {
|
||||
int32_t index = 0;
|
||||
bool isPrevOptr;
|
||||
SSQLToken sToken = {0};
|
||||
|
@ -418,6 +418,7 @@ int tsParseOneRowData(char **str, STableDataBlocks *pDataBlocks, SSchema schema[
|
|||
}
|
||||
|
||||
strcpy(error, "client out of memory");
|
||||
*code = TSDB_CODE_CLI_OUT_OF_MEMORY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -425,23 +426,42 @@ int tsParseOneRowData(char **str, STableDataBlocks *pDataBlocks, SSchema schema[
|
|||
(sToken.type != TK_FLOAT) && (sToken.type != TK_BOOL) && (sToken.type != TK_NULL)) ||
|
||||
(sToken.n == 0) || (sToken.type == TK_RP)) {
|
||||
tscInvalidSQLErrMsg(error, "invalid data or symbol", sToken.z);
|
||||
*code = TSDB_CODE_INVALID_SQL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Remove quotation marks
|
||||
if (TK_STRING == sToken.type) {
|
||||
sToken.z++;
|
||||
sToken.n -= 2;
|
||||
// delete escape character: \\, \', \"
|
||||
char delim = sToken.z[0];
|
||||
int32_t cnt = 0;
|
||||
int32_t j = 0;
|
||||
for (int32_t i = 1; i < sToken.n - 1; ++i) {
|
||||
if (sToken.z[i] == delim || sToken.z[i] == '\\') {
|
||||
if (sToken.z[i + 1] == delim) {
|
||||
cnt++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
tmpTokenBuf[j] = sToken.z[i];
|
||||
j++;
|
||||
}
|
||||
tmpTokenBuf[j] = 0;
|
||||
sToken.z = tmpTokenBuf;
|
||||
sToken.n -= 2 + cnt;
|
||||
}
|
||||
|
||||
bool isPrimaryKey = (colIndex == PRIMARYKEY_TIMESTAMP_COL_INDEX);
|
||||
int32_t ret = tsParseOneColumnData(pSchema, &sToken, start, error, str, isPrimaryKey, timePrec);
|
||||
if (ret != TSDB_CODE_SUCCESS) {
|
||||
*code = TSDB_CODE_INVALID_SQL;
|
||||
return -1; // NOTE: here 0 mean error!
|
||||
}
|
||||
|
||||
if (isPrimaryKey && tsCheckTimestamp(pDataBlocks, start) != TSDB_CODE_SUCCESS) {
|
||||
tscInvalidSQLErrMsg(error, "client time/server time can not be mixed up", sToken.z);
|
||||
*code = TSDB_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -476,7 +496,7 @@ static int32_t rowDataCompar(const void *lhs, const void *rhs) {
|
|||
}
|
||||
|
||||
int tsParseValues(char **str, STableDataBlocks *pDataBlock, SMeterMeta *pMeterMeta, int maxRows,
|
||||
SParsedDataColInfo *spd, char *error) {
|
||||
SParsedDataColInfo *spd, char *error, int32_t *code, char* tmpTokenBuf) {
|
||||
int32_t index = 0;
|
||||
SSQLToken sToken;
|
||||
|
||||
|
@ -487,6 +507,7 @@ int tsParseValues(char **str, STableDataBlocks *pDataBlock, SMeterMeta *pMeterMe
|
|||
|
||||
if (spd->hasVal[0] == false) {
|
||||
strcpy(error, "primary timestamp column can not be null");
|
||||
*code = TSDB_CODE_INVALID_SQL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -500,12 +521,13 @@ int tsParseValues(char **str, STableDataBlocks *pDataBlock, SMeterMeta *pMeterMe
|
|||
int32_t tSize = tscAllocateMemIfNeed(pDataBlock, pMeterMeta->rowSize);
|
||||
if (0 == tSize) {
|
||||
strcpy(error, "client out of memory");
|
||||
*code = TSDB_CODE_CLI_OUT_OF_MEMORY;
|
||||
return -1;
|
||||
}
|
||||
maxRows += tSize;
|
||||
}
|
||||
|
||||
int32_t len = tsParseOneRowData(str, pDataBlock, pSchema, spd, error, precision);
|
||||
int32_t len = tsParseOneRowData(str, pDataBlock, pSchema, spd, error, precision, code, tmpTokenBuf);
|
||||
if (len <= 0) { // error message has been set in tsParseOneRowData
|
||||
return -1;
|
||||
}
|
||||
|
@ -517,6 +539,7 @@ int tsParseValues(char **str, STableDataBlocks *pDataBlock, SMeterMeta *pMeterMe
|
|||
*str += index;
|
||||
if (sToken.n == 0 || sToken.type != TK_RP) {
|
||||
tscInvalidSQLErrMsg(error, ") expected", *str);
|
||||
*code = TSDB_CODE_INVALID_SQL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -525,6 +548,7 @@ int tsParseValues(char **str, STableDataBlocks *pDataBlock, SMeterMeta *pMeterMe
|
|||
|
||||
if (numOfRows <= 0) {
|
||||
strcpy(error, "no any data points");
|
||||
*code = TSDB_CODE_INVALID_SQL;
|
||||
return -1;
|
||||
} else {
|
||||
return numOfRows;
|
||||
|
@ -636,10 +660,17 @@ static int32_t doParseInsertStatement(SSqlObj *pSql, void *pTableHashList, char
|
|||
if (0 == maxNumOfRows) {
|
||||
return TSDB_CODE_CLI_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t numOfRows = tsParseValues(str, dataBuf, pMeterMeta, maxNumOfRows, spd, pCmd->payload);
|
||||
|
||||
int32_t code = TSDB_CODE_INVALID_SQL;
|
||||
char* tmpTokenBuf = calloc(1, 4096); // used for deleting Escape character: \\, \', \"
|
||||
if (NULL == tmpTokenBuf) {
|
||||
return TSDB_CODE_CLI_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t numOfRows = tsParseValues(str, dataBuf, pMeterMeta, maxNumOfRows, spd, pCmd->payload, &code, tmpTokenBuf);
|
||||
free(tmpTokenBuf);
|
||||
if (numOfRows <= 0) {
|
||||
return TSDB_CODE_INVALID_SQL;
|
||||
return code;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < dataBuf->numOfParams; ++i) {
|
||||
|
@ -1173,7 +1204,7 @@ static int doPackSendDataBlock(SSqlObj *pSql, int32_t numOfRows, STableDataBlock
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int tscInsertDataFromFile(SSqlObj *pSql, FILE *fp) {
|
||||
static int tscInsertDataFromFile(SSqlObj *pSql, FILE *fp, char *tmpTokenBuf) {
|
||||
size_t readLen = 0;
|
||||
char * line = NULL;
|
||||
size_t n = 0;
|
||||
|
@ -1216,10 +1247,10 @@ static int tscInsertDataFromFile(SSqlObj *pSql, FILE *fp) {
|
|||
maxRows += tSize;
|
||||
}
|
||||
|
||||
len = tsParseOneRowData(&lineptr, pTableDataBlock, pSchema, &spd, pCmd->payload, pMeterMeta->precision);
|
||||
len = tsParseOneRowData(&lineptr, pTableDataBlock, pSchema, &spd, pCmd->payload, pMeterMeta->precision, &code, tmpTokenBuf);
|
||||
if (len <= 0 || pTableDataBlock->numOfParams > 0) {
|
||||
pSql->res.code = TSDB_CODE_INVALID_SQL;
|
||||
return -1;
|
||||
pSql->res.code = code;
|
||||
return (-code);
|
||||
}
|
||||
|
||||
pTableDataBlock->size += len;
|
||||
|
@ -1348,8 +1379,16 @@ void tscProcessMultiVnodesInsertForFile(SSqlObj *pSql) {
|
|||
tscError("%p get meter meta failed, abort", pSql);
|
||||
continue;
|
||||
}
|
||||
|
||||
char* tmpTokenBuf = calloc(1, 4096); // used for deleting Escape character: \\, \', \"
|
||||
if (NULL == tmpTokenBuf) {
|
||||
tscError("%p calloc failed", pSql);
|
||||
continue;
|
||||
}
|
||||
|
||||
int nrows = tscInsertDataFromFile(pSql, fp);
|
||||
int nrows = tscInsertDataFromFile(pSql, fp, tmpTokenBuf);
|
||||
free(tmpTokenBuf);
|
||||
|
||||
pCmd->pDataBlocks = tscDestroyBlockArrayList(pCmd->pDataBlocks);
|
||||
|
||||
if (nrows < 0) {
|
||||
|
|
|
@ -0,0 +1,329 @@
|
|||
|
||||
## TAOS-JDBCDriver 概述
|
||||
|
||||
TDengine 为了方便 Java 应用使用,提供了遵循 JDBC 标准(3.0)API 规范的 `taos-jdbcdriver` 实现。目前可以通过 [Sonatype Repository][1] 搜索并下载。
|
||||
|
||||
由于 TDengine 是使用 c 语言开发的,使用 taos-jdbcdriver 驱动包时需要依赖系统对应的本地函数库。
|
||||
|
||||
* libtaos.so
|
||||
在 linux 系统中成功安装 TDengine 后,依赖的本地函数库 libtaos.so 文件会被自动拷贝至 /usr/lib/libtaos.so,该目录包含在 Linux 自动扫描路径上,无需单独指定。
|
||||
|
||||
* taos.dll
|
||||
在 windows 系统中安装完客户端之后,驱动包依赖的 taos.dll 文件会自动拷贝到系统默认搜索路径 C:/Windows/System32 下,同样无需要单独指定。
|
||||
|
||||
> 注意:在 windows 环境开发时需要安装 TDengine 对应的 windows 版本客户端,由于目前没有提供 Linux 环境单独的客户端,需要安装 TDengine 才能使用。
|
||||
|
||||
TDengine 的 JDBC 驱动实现尽可能的与关系型数据库驱动保持一致,但时序空间数据库与关系对象型数据库服务的对象和技术特征的差异导致 taos-jdbcdriver 并未完全实现 JDBC 标准规范。在使用时需要注意以下几点:
|
||||
|
||||
* TDengine 不提供针对单条数据记录的删除和修改的操作,驱动中也没有支持相关方法。
|
||||
* 由于不支持删除和修改,所以也不支持事务操作。
|
||||
* 目前不支持表间的 union 操作。
|
||||
* 目前不支持嵌套查询(nested query),`对每个 Connection 的实例,至多只能有一个打开的 ResultSet 实例;如果在 ResultSet还没关闭的情况下执行了新的查询,TSDBJDBCDriver 则会自动关闭上一个 ResultSet`。
|
||||
|
||||
|
||||
## TAOS-JDBCDriver 版本以及支持的 TDengine 版本和 JDK 版本
|
||||
|
||||
| taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 |
|
||||
| --- | --- | --- |
|
||||
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.1 | 1.6.1.x 及以上 | 1.8.x |
|
||||
|
||||
## TDengine DataType 和 Java DataType
|
||||
|
||||
TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对应类型转换如下:
|
||||
|
||||
| TDengine DataType | Java DataType |
|
||||
| --- | --- |
|
||||
| TIMESTAMP | java.sql.Timestamp |
|
||||
| INT | java.lang.Integer |
|
||||
| BIGINT | java.lang.Long |
|
||||
| FLOAT | java.lang.Float |
|
||||
| DOUBLE | java.lang.Double |
|
||||
| SMALLINT, TINYINT |java.lang.Short |
|
||||
| BOOL | java.lang.Boolean |
|
||||
| BINARY, NCHAR | java.lang.String |
|
||||
|
||||
## 如何获取 TAOS-JDBCDriver
|
||||
|
||||
### maven 仓库
|
||||
|
||||
目前 taos-jdbcdriver 已经发布到 [Sonatype Repository][1] 仓库,且各大仓库都已同步。
|
||||
* [sonatype][8]
|
||||
* [mvnrepository][9]
|
||||
* [maven.aliyun][10]
|
||||
|
||||
maven 项目中使用如下 pom.xml 配置即可:
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>taos-jdbcdriver</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
### 源码编译打包
|
||||
|
||||
下载 [TDengine][3] 源码之后,进入 taos-jdbcdriver 源码目录 `src/connector/jdbc` 执行 `mvn clean package` 即可生成相应 jar 包。
|
||||
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 获取连接
|
||||
|
||||
如下所示配置即可获取 TDengine Connection:
|
||||
```java
|
||||
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||
String jdbcUrl = "jdbc:TAOS://127.0.0.1:6030/log?user=root&password=taosdata";
|
||||
Connection conn = DriverManager.getConnection(jdbcUrl);
|
||||
```
|
||||
> 端口 6030 为默认连接端口,JDBC URL 中的 log 为系统本身的监控数据库。
|
||||
|
||||
TDengine 的 JDBC URL 规范格式为:
|
||||
`jdbc:TSDB://{host_ip}:{port}/[database_name]?[user={user}|&password={password}|&charset={charset}|&cfgdir={config_dir}|&locale={locale}|&timezone={timezone}]`
|
||||
|
||||
其中,`{}` 中的内容必须,`[]` 中为可选。配置参数说明如下:
|
||||
|
||||
* user:登录 TDengine 用户名,默认值 root。
|
||||
* password:用户登录密码,默认值 taosdata。
|
||||
* charset:客户端使用的字符集,默认值为系统字符集。
|
||||
* cfgdir:客户端配置文件目录路径,Linux OS 上默认值 /etc/taos ,Windows OS 上默认值 C:/TDengine/cfg。
|
||||
* locale:客户端语言环境,默认值系统当前 locale。
|
||||
* timezone:客户端使用的时区,默认值为系统当前时区。
|
||||
|
||||
以上参数可以在 3 处配置,`优先级由高到低`分别如下:
|
||||
1. JDBC URL 参数
|
||||
如上所述,可以在 JDBC URL 的参数中指定。
|
||||
2. java.sql.DriverManager.getConnection(String jdbcUrl, Properties connProps)
|
||||
```java
|
||||
public Connection getConn() throws Exception{
|
||||
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||
String jdbcUrl = "jdbc:TAOS://127.0.0.1:0/log?user=root&password=taosdata";
|
||||
Properties connProps = new Properties();
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_USER, "root");
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, "taosdata");
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_CONFIG_DIR, "/etc/taos");
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||
connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||
Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
|
||||
return conn;
|
||||
}
|
||||
```
|
||||
|
||||
3. 客户端配置文件 taos.cfg
|
||||
|
||||
linux 系统默认配置文件为 /var/lib/taos/taos.cfg,windows 系统默认配置文件路径为 C:\TDengine\cfg\taos.cfg。
|
||||
```properties
|
||||
# client default username
|
||||
# defaultUser root
|
||||
|
||||
# client default password
|
||||
# defaultPass taosdata
|
||||
|
||||
# default system charset
|
||||
# charset UTF-8
|
||||
|
||||
# system locale
|
||||
# locale en_US.UTF-8
|
||||
```
|
||||
> 更多详细配置请参考[客户端配置][13]
|
||||
|
||||
### 创建数据库和表
|
||||
|
||||
```java
|
||||
Statement stmt = conn.createStatement();
|
||||
|
||||
// create database
|
||||
stmt.executeUpdate("create database if not exists db");
|
||||
|
||||
// use database
|
||||
stmt.executeUpdate("use db");
|
||||
|
||||
// create table
|
||||
stmt.executeUpdate("create table if not exists tb (ts timestamp, temperature int, humidity float)");
|
||||
```
|
||||
> 注意:如果不使用 `use db` 指定数据库,则后续对表的操作都需要增加数据库名称作为前缀,如 db.tb。
|
||||
|
||||
### 插入数据
|
||||
|
||||
```java
|
||||
// insert data
|
||||
int affectedRows = stmt.executeUpdate("insert into tb values(now, 23, 10.3) (now + 1s, 20, 9.3)");
|
||||
|
||||
System.out.println("insert " + affectedRows + " rows.");
|
||||
```
|
||||
> now 为系统内部函数,默认为服务器当前时间。
|
||||
> `now + 1s` 代表服务器当前时间往后加 1 秒,数字后面代表时间单位:a(毫秒), s(秒), m(分), h(小时), d(天),w(周), n(月), y(年)。
|
||||
|
||||
### 查询数据
|
||||
|
||||
```java
|
||||
// query data
|
||||
ResultSet resultSet = stmt.executeQuery("select * from tb");
|
||||
|
||||
Timestamp ts = null;
|
||||
int temperature = 0;
|
||||
float humidity = 0;
|
||||
while(resultSet.next()){
|
||||
|
||||
ts = resultSet.getTimestamp(1);
|
||||
temperature = resultSet.getInt(2);
|
||||
humidity = resultSet.getFloat("humidity");
|
||||
|
||||
System.out.printf("%s, %d, %s\n", ts, temperature, humidity);
|
||||
}
|
||||
```
|
||||
> 查询和操作关系型数据库一致,使用下标获取返回字段内容时从 1 开始,建议使用字段名称获取。
|
||||
|
||||
|
||||
### 关闭资源
|
||||
|
||||
```java
|
||||
resultSet.close();
|
||||
stmt.close();
|
||||
conn.close();
|
||||
```
|
||||
> `注意务必要将 connection 进行关闭`,否则会出现连接泄露。
|
||||
## 与连接池使用
|
||||
|
||||
**HikariCP**
|
||||
|
||||
* 引入相应 HikariCP maven 依赖:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
* 使用示例如下:
|
||||
```java
|
||||
public static void main(String[] args) throws SQLException {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl("jdbc:TAOS://127.0.0.1:6030/log");
|
||||
config.setUsername("root");
|
||||
config.setPassword("taosdata");
|
||||
|
||||
config.setMinimumIdle(3); //minimum number of idle connection
|
||||
config.setMaximumPoolSize(10); //maximum number of connection in the pool
|
||||
config.setConnectionTimeout(10000); //maximum wait milliseconds for get connection from pool
|
||||
config.setIdleTimeout(60000); // max idle time for recycle idle connection
|
||||
config.setConnectionTestQuery("describe log.dn"); //validation query
|
||||
config.setValidationTimeout(3000); //validation query timeout
|
||||
|
||||
HikariDataSource ds = new HikariDataSource(config); //create datasource
|
||||
|
||||
Connection connection = ds.getConnection(); // get connection
|
||||
Statement statement = connection.createStatement(); // get statement
|
||||
|
||||
//query or insert
|
||||
// ...
|
||||
|
||||
connection.close(); // put back to conneciton pool
|
||||
}
|
||||
```
|
||||
> 通过 HikariDataSource.getConnection() 获取连接后,使用完成后需要调用 close() 方法,实际上它并不会关闭连接,只是放回连接池中。
|
||||
> 更多 HikariCP 使用问题请查看[官方说明][5]
|
||||
|
||||
**Druid**
|
||||
|
||||
* 引入相应 Druid maven 依赖:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.1.20</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
* 使用示例如下:
|
||||
```java
|
||||
public static void main(String[] args) throws Exception {
|
||||
Properties properties = new Properties();
|
||||
properties.put("driverClassName","com.taosdata.jdbc.TSDBDriver");
|
||||
properties.put("url","jdbc:TAOS://127.0.0.1:6030/log");
|
||||
properties.put("username","root");
|
||||
properties.put("password","taosdata");
|
||||
|
||||
properties.put("maxActive","10"); //maximum number of connection in the pool
|
||||
properties.put("initialSize","3");//initial number of connection
|
||||
properties.put("maxWait","10000");//maximum wait milliseconds for get connection from pool
|
||||
properties.put("minIdle","3");//minimum number of connection in the pool
|
||||
|
||||
properties.put("timeBetweenEvictionRunsMillis","3000");// the interval milliseconds to test connection
|
||||
|
||||
properties.put("minEvictableIdleTimeMillis","60000");//the minimum milliseconds to keep idle
|
||||
properties.put("maxEvictableIdleTimeMillis","90000");//the maximum milliseconds to keep idle
|
||||
|
||||
properties.put("validationQuery","describe log.dn"); //validation query
|
||||
properties.put("testWhileIdle","true"); // test connection while idle
|
||||
properties.put("testOnBorrow","false"); // don't need while testWhileIdle is true
|
||||
properties.put("testOnReturn","false"); // don't need while testWhileIdle is true
|
||||
|
||||
//create druid datasource
|
||||
DataSource ds = DruidDataSourceFactory.createDataSource(properties);
|
||||
Connection connection = ds.getConnection(); // get connection
|
||||
Statement statement = connection.createStatement(); // get statement
|
||||
|
||||
//query or insert
|
||||
// ...
|
||||
|
||||
connection.close(); // put back to conneciton pool
|
||||
}
|
||||
```
|
||||
> 更多 druid 使用问题请查看[官方说明][6]
|
||||
|
||||
**注意事项**
|
||||
* TDengine `v1.6.4.1` 版本开始提供了一个专门用于心跳检测的函数 `select server_status()`,所以在使用连接池时推荐使用 `select server_status()` 进行 Validation Query。
|
||||
|
||||
如下所示,`select server_status()` 执行成功会返回 `1`。
|
||||
```shell
|
||||
taos> select server_status();
|
||||
server_status()|
|
||||
================
|
||||
1 |
|
||||
Query OK, 1 row(s) in set (0.000141s)
|
||||
```
|
||||
|
||||
## 与框架使用
|
||||
|
||||
* Spring JdbcTemplate 中使用 taos-jdbcdriver,可参考 [SpringJdbcTemplate][11]
|
||||
* Springboot + Mybatis 中使用,可参考 [springbootdemo][12]
|
||||
|
||||
## 常见问题
|
||||
|
||||
* java.lang.UnsatisfiedLinkError: no taos in java.library.path
|
||||
|
||||
**原因**:程序没有找到依赖的本地函数库 taos。
|
||||
|
||||
**解决方法**:windows 下可以将 C:\TDengine\driver\taos.dll 拷贝到 C:\Windows\System32\ 目录下,linux 下将建立如下软链 ` ln -s /usr/local/taos/driver/libtaos.so.x.x.x.x /usr/lib/libtaos.so` 即可。
|
||||
|
||||
* java.lang.UnsatisfiedLinkError: taos.dll Can't load AMD 64 bit on a IA 32-bit platform
|
||||
|
||||
**原因**:目前 TDengine 只支持 64 位 JDK。
|
||||
|
||||
**解决方法**:重新安装 64 位 JDK。
|
||||
|
||||
* 其它问题请参考 [Issues][7]
|
||||
|
||||
|
||||
|
||||
[1]: https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[2]: https://mvnrepository.com/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[3]: https://github.com/taosdata/TDengine
|
||||
[4]: https://www.taosdata.com/blog/2019/12/03/jdbcdriver%e6%89%be%e4%b8%8d%e5%88%b0%e5%8a%a8%e6%80%81%e9%93%be%e6%8e%a5%e5%ba%93/
|
||||
[5]: https://github.com/brettwooldridge/HikariCP
|
||||
[6]: https://github.com/alibaba/druid
|
||||
[7]: https://github.com/taosdata/TDengine/issues
|
||||
[8]: https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[9]: https://mvnrepository.com/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[10]: https://maven.aliyun.com/mvn/search
|
||||
[11]: https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/SpringJdbcTemplate
|
||||
[12]: https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/springbootdemo
|
||||
[13]: https://www.taosdata.com/cn/documentation/administrator/#%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE
|
|
@ -151,6 +151,8 @@ void shellReplaceCtrlChar(char *str) {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
*pstr = *str;
|
||||
pstr++;
|
||||
break;
|
||||
}
|
||||
ctrlOn = false;
|
||||
|
|
|
@ -171,6 +171,7 @@ int sdbInitTableByFile(SSdbTable *pTable) {
|
|||
void * pMetaRow = NULL;
|
||||
int total_size = 0;
|
||||
int real_size = 0;
|
||||
int maxAutoIndex = 0;
|
||||
|
||||
oldId = pTable->id;
|
||||
if (sdbOpenSdbFile(pTable) < 0) return -1;
|
||||
|
@ -240,10 +241,18 @@ int sdbInitTableByFile(SSdbTable *pTable) {
|
|||
rowMeta.rowSize = rowHead->rowSize;
|
||||
rowMeta.row = (*(pTable->appTool))(SDB_TYPE_DECODE, NULL, rowHead->data, rowHead->rowSize, NULL);
|
||||
(*sdbAddIndexFp[pTable->keyType])(pTable->iHandle, rowMeta.row, &rowMeta);
|
||||
if (pTable->keyType == SDB_KEYTYPE_AUTO) pTable->autoIndex++;
|
||||
if (pTable->keyType == SDB_KEYTYPE_AUTO) {
|
||||
pTable->autoIndex++;
|
||||
maxAutoIndex = MAX(maxAutoIndex, *(int32_t*)rowHead->data);
|
||||
}
|
||||
pTable->numOfRows++;
|
||||
}
|
||||
} else { // already exists
|
||||
if (pTable->keyType == SDB_KEYTYPE_AUTO) {
|
||||
pTable->autoIndex++;
|
||||
maxAutoIndex = MAX(maxAutoIndex, *(int32_t *) rowHead->data);
|
||||
}
|
||||
|
||||
if (rowHead->id < 0) { // Delete the object
|
||||
(*sdbDeleteIndexFp[pTable->keyType])(pTable->iHandle, rowHead->data);
|
||||
(*(pTable->appTool))(SDB_TYPE_DESTROY, pMetaRow, NULL, 0, NULL);
|
||||
|
@ -260,6 +269,10 @@ int sdbInitTableByFile(SSdbTable *pTable) {
|
|||
if (pTable->id < abs(rowHead->id)) pTable->id = abs(rowHead->id);
|
||||
}
|
||||
|
||||
if (pTable->keyType == SDB_KEYTYPE_AUTO) {
|
||||
pTable->autoIndex = maxAutoIndex;
|
||||
}
|
||||
|
||||
sdbVersion += (pTable->id - oldId);
|
||||
if (numOfDels > pTable->maxRows / 4) sdbSaveSnapShot(pTable);
|
||||
|
||||
|
|
|
@ -233,6 +233,10 @@ void *mgmtMeterActionDelete(void *row, char *str, int size, int *ssize) {
|
|||
pMeter = (STabObj *)row;
|
||||
|
||||
if (mgmtIsNormalMeter(pMeter)) {
|
||||
if (pMeter->gid.vgId == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pVgroup = mgmtGetVgroup(pMeter->gid.vgId);
|
||||
if (pVgroup == NULL) {
|
||||
mError("id:%s not in vgroup:%d", pMeter->meterId, pMeter->gid.vgId);
|
||||
|
@ -426,6 +430,7 @@ void mgmtAddMeterStatisticToAcct(STabObj *pMeter, SAcctObj *pAcct) {
|
|||
|
||||
int mgmtInitMeters() {
|
||||
void * pNode = NULL;
|
||||
void * pLastNode = NULL;
|
||||
SVgObj * pVgroup = NULL;
|
||||
STabObj * pMeter = NULL;
|
||||
STabObj * pMetric = NULL;
|
||||
|
@ -451,21 +456,47 @@ int mgmtInitMeters() {
|
|||
|
||||
pNode = NULL;
|
||||
while (1) {
|
||||
pLastNode = pNode;
|
||||
pNode = sdbFetchRow(meterSdb, pNode, (void **)&pMeter);
|
||||
if (pMeter == NULL) break;
|
||||
|
||||
pDb = mgmtGetDbByMeterId(pMeter->meterId);
|
||||
if (pDb == NULL) {
|
||||
mError("failed to get db: %s", pMeter->meterId);
|
||||
mError("meter:%s, failed to get db, discard it", pMeter->meterId, pMeter->gid.vgId, pMeter->gid.sid);
|
||||
pMeter->gid.vgId = 0;
|
||||
sdbDeleteRow(meterSdb, pMeter);
|
||||
pNode = pLastNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mgmtIsNormalMeter(pMeter)) {
|
||||
pVgroup = mgmtGetVgroup(pMeter->gid.vgId);
|
||||
if (pVgroup == NULL || pVgroup->meterList == NULL) {
|
||||
mError("failed to get vgroup:%i", pMeter->gid.vgId);
|
||||
|
||||
if (pVgroup == NULL) {
|
||||
mError("meter:%s, failed to get vgroup:%d sid:%d, discard it", pMeter->meterId, pMeter->gid.vgId, pMeter->gid.sid);
|
||||
pMeter->gid.vgId = 0;
|
||||
sdbDeleteRow(meterSdb, pMeter);
|
||||
pNode = pLastNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(pVgroup->dbName, pDb->name) != 0) {
|
||||
mError("meter:%s, db:%s not match with vgroup:%d db:%s sid:%d, discard it",
|
||||
pMeter->meterId, pDb->name, pMeter->gid.vgId, pVgroup->dbName, pMeter->gid.sid);
|
||||
pMeter->gid.vgId = 0;
|
||||
sdbDeleteRow(meterSdb, pMeter);
|
||||
pNode = pLastNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( pVgroup->meterList == NULL) {
|
||||
mError("meter:%s, vgroup:%d meterlist is null", pMeter->meterId, pMeter->gid.vgId);
|
||||
pMeter->gid.vgId = 0;
|
||||
sdbDeleteRow(meterSdb, pMeter);
|
||||
pNode = pLastNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
pVgroup->meterList[pMeter->gid.sid] = pMeter;
|
||||
taosIdPoolMarkStatus(pVgroup->idPool, pMeter->gid.sid, 1);
|
||||
|
||||
|
|
|
@ -1254,6 +1254,7 @@ int vnodeWriteBlockToFile(SMeterObj *pObj, SCompBlock *pCompBlock, SData *data[]
|
|||
offset += (cdata[i]->len + sizeof(TSCKSUM));
|
||||
|
||||
} else {
|
||||
data[i]->len = pObj->schema[i].bytes * points;
|
||||
fields[i].len = data[i]->len;
|
||||
taosCalcChecksumAppend(0, (uint8_t *)(data[i]->data), data[i]->len + sizeof(TSCKSUM));
|
||||
offset += (data[i]->len + sizeof(TSCKSUM));
|
||||
|
|
|
@ -254,13 +254,13 @@ static void processExpiredTimer(void* handle, void* arg) {
|
|||
timer->executedBy = taosGetPthreadId();
|
||||
uint8_t state = atomic_val_compare_exchange_8(&timer->state, TIMER_STATE_WAITING, TIMER_STATE_EXPIRED);
|
||||
if (state == TIMER_STATE_WAITING) {
|
||||
const char* fmt = "%s timer[id=" PRIuPTR ", fp=%p, param=%p] execution start.";
|
||||
const char* fmt = "%s timer[id=%" PRIuPTR ", fp=%p, param=%p] execution start.";
|
||||
tmrTrace(fmt, timer->ctrl->label, timer->id, timer->fp, timer->param);
|
||||
|
||||
(*timer->fp)(timer->param, (tmr_h)timer->id);
|
||||
atomic_store_8(&timer->state, TIMER_STATE_STOPPED);
|
||||
|
||||
fmt = "%s timer[id=" PRIuPTR ", fp=%p, param=%p] execution end.";
|
||||
fmt = "%s timer[id=%" PRIuPTR ", fp=%p, param=%p] execution end.";
|
||||
tmrTrace(fmt, timer->ctrl->label, timer->id, timer->fp, timer->param);
|
||||
}
|
||||
removeTimer(timer->id);
|
||||
|
@ -268,7 +268,7 @@ static void processExpiredTimer(void* handle, void* arg) {
|
|||
}
|
||||
|
||||
static void addToExpired(tmr_obj_t* head) {
|
||||
const char* fmt = "%s adding expired timer[id=" PRIuPTR ", fp=%p, param=%p] to queue.";
|
||||
const char* fmt = "%s adding expired timer[id=%" PRIuPTR ", fp=%p, param=%p] to queue.";
|
||||
|
||||
while (head != NULL) {
|
||||
uintptr_t id = head->id;
|
||||
|
@ -282,7 +282,7 @@ static void addToExpired(tmr_obj_t* head) {
|
|||
schedMsg.thandle = NULL;
|
||||
taosScheduleTask(tmrQhandle, &schedMsg);
|
||||
|
||||
tmrTrace("timer[id=" PRIuPTR "] has been added to queue.", id);
|
||||
tmrTrace("timer[id=%" PRIuPTR "] has been added to queue.", id);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ static uintptr_t doStartTimer(tmr_obj_t* timer, TAOS_TMR_CALLBACK fp, int msecon
|
|||
timer->ctrl = ctrl;
|
||||
addTimer(timer);
|
||||
|
||||
const char* fmt = "%s timer[id=" PRIuPTR ", fp=%p, param=%p] started";
|
||||
const char* fmt = "%s timer[id=%" PRIuPTR ", fp=%p, param=%p] started";
|
||||
tmrTrace(fmt, ctrl->label, timer->id, timer->fp, timer->param);
|
||||
|
||||
if (mseconds == 0) {
|
||||
|
@ -389,7 +389,7 @@ static bool doStopTimer(tmr_obj_t* timer, uint8_t state) {
|
|||
// we cannot guarantee the thread safety of the timr in all other cases.
|
||||
reusable = true;
|
||||
}
|
||||
const char* fmt = "%s timer[id=" PRIuPTR ", fp=%p, param=%p] is cancelled.";
|
||||
const char* fmt = "%s timer[id=%" PRIuPTR ", fp=%p, param=%p] is cancelled.";
|
||||
tmrTrace(fmt, timer->ctrl->label, timer->id, timer->fp, timer->param);
|
||||
return reusable;
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ static bool doStopTimer(tmr_obj_t* timer, uint8_t state) {
|
|||
// timer callback is executing in another thread, we SHOULD wait it to stop,
|
||||
// BUT this may result in dead lock if current thread are holding a lock which
|
||||
// the timer callback need to acquire. so, we HAVE TO return directly.
|
||||
const char* fmt = "%s timer[id=" PRIuPTR ", fp=%p, param=%p] is executing and cannot be stopped.";
|
||||
const char* fmt = "%s timer[id=%" PRIuPTR ", fp=%p, param=%p] is executing and cannot be stopped.";
|
||||
tmrTrace(fmt, timer->ctrl->label, timer->id, timer->fp, timer->param);
|
||||
return false;
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ bool taosTmrStop(tmr_h timerId) {
|
|||
|
||||
tmr_obj_t* timer = findTimer(id);
|
||||
if (timer == NULL) {
|
||||
tmrTrace("timer[id=" PRIuPTR "] does not exist", id);
|
||||
tmrTrace("timer[id=%" PRIuPTR "] does not exist", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -446,7 +446,7 @@ bool taosTmrReset(TAOS_TMR_CALLBACK fp, int mseconds, void* param, void* handle,
|
|||
bool stopped = false;
|
||||
tmr_obj_t* timer = findTimer(id);
|
||||
if (timer == NULL) {
|
||||
tmrTrace("%s timer[id=" PRIuPTR "] does not exist", ctrl->label, id);
|
||||
tmrTrace("%s timer[id=%" PRIuPTR "] does not exist", ctrl->label, id);
|
||||
} else {
|
||||
uint8_t state = atomic_val_compare_exchange_8(&timer->state, TIMER_STATE_WAITING, TIMER_STATE_CANCELED);
|
||||
if (!doStopTimer(timer, state)) {
|
||||
|
@ -461,7 +461,7 @@ bool taosTmrReset(TAOS_TMR_CALLBACK fp, int mseconds, void* param, void* handle,
|
|||
return stopped;
|
||||
}
|
||||
|
||||
tmrTrace("%s timer[id=" PRIuPTR "] is reused", ctrl->label, timer->id);
|
||||
tmrTrace("%s timer[id=%" PRIuPTR "] is reused", ctrl->label, timer->id);
|
||||
|
||||
// wait until there's no other reference to this timer,
|
||||
// so that we can reuse this timer safely.
|
||||
|
|
|
@ -418,7 +418,12 @@ uint32_t tSQLGetToken(char* z, uint32_t* tokenType) {
|
|||
int delim = z[0];
|
||||
bool strEnd = false;
|
||||
for (i = 1; z[i]; i++) {
|
||||
if (z[i] == delim) {
|
||||
if (z[i] == '\\') {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z[i] == delim ) {
|
||||
if (z[i + 1] == delim) {
|
||||
i++;
|
||||
} else {
|
||||
|
@ -427,6 +432,7 @@ uint32_t tSQLGetToken(char* z, uint32_t* tokenType) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (z[i]) i++;
|
||||
|
||||
if (strEnd) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
HELP.md
|
||||
target/
|
||||
.mvn/
|
||||
!**/src/main/**
|
||||
!**/src/test/**
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>SpringJdbcTemplate</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>SpringJdbcTemplate</name>
|
||||
<url>http://www.taosdata.com</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>4.3.2.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>4.3.2.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>taos-jdbcdriver</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.taosdata.jdbc.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
## TDengine Spring JDBC Template Demo
|
||||
|
||||
`Spring JDBC Template` 简化了原生 JDBC Connection 获取释放等操作,使得操作数据库更加方便。
|
||||
|
||||
### 配置
|
||||
|
||||
修改 `src/main/resources/applicationContext.xml` 文件中 TDengine 的配置信息:
|
||||
|
||||
```xml
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="com.taosdata.jdbc.TSDBDriver"></property>
|
||||
<property name="url" value="jdbc:TAOS://127.0.0.1:6030/log"></property>
|
||||
<property name="username" value="root"></property>
|
||||
<property name="password" value="taosdata"></property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id = "jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
|
||||
<property name="dataSource" ref = "dataSource" ></property>
|
||||
</bean>
|
||||
```
|
||||
|
||||
### 打包运行
|
||||
|
||||
进入 `TDengine/tests/examples/JDBC/SpringJdbcTemplate` 目录下,执行以下命令可以生成可执行 jar 包。
|
||||
```shell
|
||||
mvn clean package
|
||||
```
|
||||
打包成功之后,进入 `target/` 目录下,执行以下命令就可运行测试:
|
||||
```shell
|
||||
java -jar SpringJdbcTemplate-1.0-SNAPSHOT-jar-with-dependencies.jar
|
||||
```
|
|
@ -0,0 +1,44 @@
|
|||
package com.taosdata.jdbc;
|
||||
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class App {
|
||||
|
||||
public static void main( String[] args ) {
|
||||
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
|
||||
|
||||
JdbcTemplate jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
|
||||
|
||||
// create database
|
||||
jdbcTemplate.execute("create database if not exists db ");
|
||||
|
||||
// create table
|
||||
jdbcTemplate.execute("create table if not exists db.tb (ts timestamp, temperature int, humidity float)");
|
||||
|
||||
String insertSql = "insert into db.tb values(now, 23, 10.3) (now + 1s, 20, 9.3)";
|
||||
|
||||
// insert rows
|
||||
int affectedRows = jdbcTemplate.update(insertSql);
|
||||
|
||||
System.out.println("insert success " + affectedRows + " rows.");
|
||||
|
||||
// query for list
|
||||
List<Map<String, Object>> resultList = jdbcTemplate.queryForList("select * from db.tb");
|
||||
|
||||
if(!CollectionUtils.isEmpty(resultList)){
|
||||
for (Map<String, Object> row : resultList){
|
||||
System.out.printf("%s, %d, %s\n", row.get("ts"), row.get("temperature"), row.get("humidity"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
"
|
||||
default-autowire="byName">
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="com.taosdata.jdbc.TSDBDriver"></property>
|
||||
<property name="url" value="jdbc:TAOS://127.0.0.1:6030/log"></property>
|
||||
<property name="username" value="root"></property>
|
||||
<property name="password" value="taosdata"></property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id = "jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
|
||||
<property name="dataSource" ref = "dataSource" ></property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,20 @@
|
|||
package com.taosdata.jdbc;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class AppTest
|
||||
{
|
||||
/**
|
||||
* Rigorous Test :-)
|
||||
*/
|
||||
@Test
|
||||
public void shouldAnswerWithTrue()
|
||||
{
|
||||
assertTrue( true );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
.mvn/
|
||||
target/
|
||||
!**/src/main/**
|
||||
!**/src/test/**
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
118
tests/examples/JDBC/springbootdemo/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
118
tests/examples/JDBC/springbootdemo/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.5";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if (mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if (mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if (!outputFile.getParentFile().exists()) {
|
||||
if (!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar
|
|
@ -0,0 +1,310 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
|
@ -0,0 +1,182 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM https://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||
|
||||
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>springbootdemo</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>springbootdemo</name>
|
||||
<description>Demo project for using tdengine with Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>taos-jdbcdriver</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.1.17</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,96 @@
|
|||
## TDengine SpringBoot + Mybatis Demo
|
||||
|
||||
### 配置 application.properties
|
||||
```properties
|
||||
# datasource config
|
||||
spring.datasource.driver-class-name=com.taosdata.jdbc.TSDBDriver
|
||||
spring.datasource.url=jdbc:TAOS://127.0.0.1:6030/log
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=taosdata
|
||||
|
||||
spring.datasource.druid.initial-size=5
|
||||
spring.datasource.druid.min-idle=5
|
||||
spring.datasource.druid.max-active=5
|
||||
# max wait time for get connection, ms
|
||||
spring.datasource.druid.max-wait=60000
|
||||
|
||||
spring.datasource.druid.validation-query=describe log.dn
|
||||
spring.datasource.druid.validation-query-timeout=5000
|
||||
spring.datasource.druid.test-on-borrow=false
|
||||
spring.datasource.druid.test-on-return=false
|
||||
spring.datasource.druid.test-while-idle=true
|
||||
spring.datasource.druid.time-between-eviction-runs-millis=60000
|
||||
spring.datasource.druid.min-evictable-idle-time-millis=600000
|
||||
spring.datasource.druid.max-evictable-idle-time-millis=900000
|
||||
|
||||
# mybatis
|
||||
mybatis.mapper-locations=classpath:mapper/*.xml
|
||||
|
||||
# log
|
||||
logging.level.com.taosdata.jdbc.springbootdemo.dao=debug
|
||||
```
|
||||
|
||||
### 主要功能
|
||||
|
||||
* 创建数据库和表
|
||||
```xml
|
||||
<!-- weatherMapper.xml -->
|
||||
<update id="createDB" >
|
||||
create database if not exists test;
|
||||
</update>
|
||||
|
||||
<update id="createTable" >
|
||||
create table if not exists test.weather(ts timestamp, temperature int, humidity float);
|
||||
</update>
|
||||
```
|
||||
|
||||
* 插入单条记录
|
||||
```xml
|
||||
<!-- weatherMapper.xml -->
|
||||
<insert id="insert" parameterType="com.taosdata.jdbc.springbootdemo.domain.Weather" >
|
||||
insert into test.weather (ts, temperature, humidity) values (now, #{temperature,jdbcType=INTEGER}, #{humidity,jdbcType=FLOAT})
|
||||
</insert>
|
||||
```
|
||||
* 插入多条记录
|
||||
```xml
|
||||
<!-- weatherMapper.xml -->
|
||||
<insert id="batchInsert" parameterType="java.util.List" >
|
||||
insert into test.weather (ts, temperature, humidity) values
|
||||
<foreach separator=" " collection="list" item="weather" index="index" >
|
||||
(now + #{index}a, #{weather.temperature}, #{weather.humidity})
|
||||
</foreach>
|
||||
</insert>
|
||||
```
|
||||
* 分页查询
|
||||
```xml
|
||||
<!-- weatherMapper.xml -->
|
||||
<?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.taosdata.jdbc.springbootdemo.dao.WeatherMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.taosdata.jdbc.springbootdemo.domain.Weather">
|
||||
<id column="ts" jdbcType="TIMESTAMP" property="ts" />
|
||||
<result column="temperature" jdbcType="INTEGER" property="temperature" />
|
||||
<result column="humidity" jdbcType="FLOAT" property="humidity" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
ts, temperature, humidity
|
||||
</sql>
|
||||
|
||||
<select id="select" resultMap="BaseResultMap">
|
||||
select
|
||||
<include refid="Base_Column_List" />
|
||||
from test.weather
|
||||
order by ts desc
|
||||
<if test="limit != null">
|
||||
limit #{limit,jdbcType=BIGINT}
|
||||
</if>
|
||||
<if test="offset != null">
|
||||
offset #{offset,jdbcType=BIGINT}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
```
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.taosdata.jdbc.springbootdemo;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@MapperScan(basePackages = {"com.taosdata.jdbc.springbootdemo.dao"})
|
||||
@SpringBootApplication
|
||||
public class SpringbootdemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringbootdemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.taosdata.jdbc.springbootdemo.controller;
|
||||
|
||||
import com.taosdata.jdbc.springbootdemo.domain.Weather;
|
||||
import com.taosdata.jdbc.springbootdemo.service.WeatherService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequestMapping("/weather")
|
||||
@RestController
|
||||
public class WeatherController {
|
||||
|
||||
@Autowired
|
||||
private WeatherService weatherService;
|
||||
|
||||
/**
|
||||
* create database and table
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/init")
|
||||
public boolean init(){
|
||||
return weatherService.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pagination Query
|
||||
* @param limit
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/{limit}/{offset}")
|
||||
public List<Weather> queryWeather(@PathVariable Long limit, @PathVariable Long offset){
|
||||
return weatherService.query(limit, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* upload single weather info
|
||||
* @param temperature
|
||||
* @param humidity
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/{temperature}/{humidity}")
|
||||
public int saveWeather(@PathVariable int temperature, @PathVariable float humidity){
|
||||
|
||||
return weatherService.save(temperature, humidity);
|
||||
}
|
||||
|
||||
/**
|
||||
* upload multi weather info
|
||||
* @param weatherList
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/batch")
|
||||
public int batchSaveWeather(@RequestBody List<Weather> weatherList){
|
||||
|
||||
return weatherService.save(weatherList);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.taosdata.jdbc.springbootdemo.dao;
|
||||
|
||||
import com.taosdata.jdbc.springbootdemo.domain.Weather;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface WeatherMapper {
|
||||
|
||||
int insert(Weather weather);
|
||||
|
||||
int batchInsert(List<Weather> weatherList);
|
||||
|
||||
List<Weather> select(@Param("limit") Long limit, @Param("offset")Long offset);
|
||||
|
||||
void createDB();
|
||||
|
||||
void createTable();
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.taosdata.jdbc.springbootdemo.domain;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
public class Weather {
|
||||
|
||||
private Timestamp ts;
|
||||
|
||||
private int temperature;
|
||||
|
||||
private float humidity;
|
||||
|
||||
public Timestamp getTs() {
|
||||
return ts;
|
||||
}
|
||||
|
||||
public void setTs(Timestamp ts) {
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
public int getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(int temperature) {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
public float getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(float humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.taosdata.jdbc.springbootdemo.service;
|
||||
|
||||
import com.taosdata.jdbc.springbootdemo.dao.WeatherMapper;
|
||||
import com.taosdata.jdbc.springbootdemo.domain.Weather;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class WeatherService {
|
||||
|
||||
@Autowired
|
||||
private WeatherMapper weatherMapper;
|
||||
|
||||
public boolean init() {
|
||||
|
||||
weatherMapper.createDB();
|
||||
weatherMapper.createTable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Weather> query(Long limit, Long offset) {
|
||||
return weatherMapper.select(limit, offset);
|
||||
}
|
||||
|
||||
public int save(int temperature, float humidity) {
|
||||
Weather weather = new Weather();
|
||||
weather.setTemperature(temperature);
|
||||
weather.setHumidity(humidity);
|
||||
|
||||
return weatherMapper.insert(weather);
|
||||
}
|
||||
|
||||
public int save(List<Weather> weatherList) {
|
||||
return weatherMapper.batchInsert(weatherList);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
# datasource config
|
||||
spring.datasource.driver-class-name=com.taosdata.jdbc.TSDBDriver
|
||||
spring.datasource.url=jdbc:TAOS://127.0.0.1:6030/log
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=taosdata
|
||||
|
||||
spring.datasource.druid.initial-size=5
|
||||
spring.datasource.druid.min-idle=5
|
||||
spring.datasource.druid.max-active=5
|
||||
# max wait time for get connection, ms
|
||||
spring.datasource.druid.max-wait=60000
|
||||
|
||||
spring.datasource.druid.validation-query=describe log.dn
|
||||
spring.datasource.druid.validation-query-timeout=5000
|
||||
spring.datasource.druid.test-on-borrow=false
|
||||
spring.datasource.druid.test-on-return=false
|
||||
spring.datasource.druid.test-while-idle=true
|
||||
spring.datasource.druid.time-between-eviction-runs-millis=60000
|
||||
spring.datasource.druid.min-evictable-idle-time-millis=600000
|
||||
spring.datasource.druid.max-evictable-idle-time-millis=900000
|
||||
|
||||
|
||||
#mybatis
|
||||
mybatis.mapper-locations=classpath:mapper/*.xml
|
||||
|
||||
logging.level.com.taosdata.jdbc.springbootdemo.dao=debug
|
|
@ -0,0 +1,49 @@
|
|||
<?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.taosdata.jdbc.springbootdemo.dao.WeatherMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.taosdata.jdbc.springbootdemo.domain.Weather">
|
||||
<id column="ts" jdbcType="TIMESTAMP" property="ts" />
|
||||
<result column="temperature" jdbcType="INTEGER" property="temperature" />
|
||||
<result column="humidity" jdbcType="FLOAT" property="humidity" />
|
||||
</resultMap>
|
||||
|
||||
<update id="createDB" >
|
||||
create database if not exists test;
|
||||
</update>
|
||||
|
||||
<update id="createTable" >
|
||||
create table if not exists test.weather(ts timestamp, temperature int, humidity float);
|
||||
</update>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
ts, temperature, humidity
|
||||
</sql>
|
||||
|
||||
<select id="select" resultMap="BaseResultMap">
|
||||
select
|
||||
<include refid="Base_Column_List" />
|
||||
from test.weather
|
||||
order by ts desc
|
||||
<if test="limit != null">
|
||||
limit #{limit,jdbcType=BIGINT}
|
||||
</if>
|
||||
<if test="offset != null">
|
||||
offset #{offset,jdbcType=BIGINT}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<insert id="insert" parameterType="com.taosdata.jdbc.springbootdemo.domain.Weather" >
|
||||
insert into test.weather (ts, temperature, humidity) values (now, #{temperature,jdbcType=INTEGER}, #{humidity,jdbcType=FLOAT})
|
||||
</insert>
|
||||
|
||||
<insert id="batchInsert" parameterType="java.util.List" >
|
||||
insert into test.weather (ts, temperature, humidity) values
|
||||
<foreach separator=" " collection="list" item="weather" index="index" >
|
||||
(now + #{index}a, #{weather.temperature}, #{weather.humidity})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,13 @@
|
|||
package com.taosdata.jdbc.springbootdemo;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class SpringbootdemoApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue