Influx提供多条语句的同时查询(Multiple queries):
curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=mydb" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west';SELECT count(\"value\") FROM \"cpu_load_short\" WHERE \"region\"='us-west'"
就是说我一次请求可以同时执行多条sql,官网明确说明只要每个sql中间用分号(;)隔开就好。
获取信息的代码:
public void getTest(){
RestTemplate restTemplate=new RestTemplate();
String url="http://localhost:8086/query?pretty=true&q=select * from pkk;select count(*) from pkk&db=mydb";
String points=restTemplate.getForObject(url,String.class);
System.out.println("points:"+points);
}
返回的信息:
points:{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "pkk",
"columns": [
"time",
"address",
"age",
"name"
],
"values": [
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
21,
"pangkun1"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
23,
"pangkun3"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
22,
"pangkun2"
]
]
}
]
}
]
}
这里可以看出上边返回的只有第一条查询语句的结果,第二条根本就没有执行,或者执行后根本就没返回。
同样的sql在InfluxDB的web端可以正常返回数据,但是放到代码中就是查询不出结果。
所以我判断问题应该是出在两条sql的连接处–分号,仔细查看curl中的url是说要encode的,现在看下web端执行成功的url:
http://localhost:8086/query?q=select+*+from+pkk%3Bselect+count(*)+from+pkk&db=mydb
通过抓包,或者直接在浏览器中执行我代码中的URL:
http://localhost:8086/query?pretty=true&q=select%20*%20from%20pkk;select%20count(*)%20from%20pkk&db=mydb
仔细对比可以发现自己执行的url中的分号(;)并没有没加密处理,在网上搜索可以看到其对应的编码为%3B。
所以,现在的问题是sping的resttemplate没有对分号进行处理。解决方案,重写resttemplate的url处理部分。
重写之后的代码:
package org.springframework.web.client;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.Assert;
import org.springframework.web.util.UriTemplateHandler;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
/**
* Created by pangkunkun on 2017/7/21.
*/
public class DisplayRestTemplate extends RestTemplate{
@Override
public T getForObject(String url, Class responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
HttpMessageConverterExtractor responseExtractor =
new HttpMessageConverterExtractor(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
// general execution
@Override
public T execute(String url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor responseExtractor, Object... uriVariables) throws RestClientException {
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
try {
//对处理完之后的url进行二次处理,;替换为%3B
expanded=new URI(expanded.toString().replace(";","%3B"));
}catch (Exception e){
e.printStackTrace();
}
return doExecute(expanded, method, requestCallback, responseExtractor);
}
/**
* Execute the given method on the provided URI.
* The {@link ClientHttpRequest} is processed using the {@link RequestCallback};
* the response with the {@link ResponseExtractor}.
* @param url the fully-expanded URL to connect to
* @param method the HTTP method to execute (GET, POST, etc.)
* @param requestCallback object that prepares the request (can be {@code null})
* @param responseExtractor object that extracts the return value from the response (can be {@code null})
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
@Override
protected T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor responseExtractor) throws RestClientException {
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
else {
return null;
}
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf(query) - 1) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
}
修改获取的代码:
public void getTest(){
DisplayRestTemplaterestTemplate=new DisplayRestTemplate();
String url="http://localhost:8086/query?pretty=true&q=select * from pkk;select count(*) from pkk&db=mydb";
String points=restTemplate.getForObject(url,String.class);
System.out.println("points:"+points);
}
修改后的结果:
points:{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "pkk",
"columns": [
"time",
"address",
"age",
"name"
],
"values": [
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
21,
"pangkun1"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
23,
"pangkun3"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
22,
"pangkun2"
]
]
}
]
},
{
"statement_id": 1,
"series": [
{
"name": "pkk",
"columns": [
"time",
"count_age"
],
"values": [
[
"1970-01-01T00:00:00Z",
3
]
]
}
]
}
]
}
现在可以看到结果是OK的,正常返回了两个查询语句的信息。
现在再来看看两个表之间的一次查询:
再创建另外一个measurement:
public void writePoints(){
String url="http://localhost:8086/write?db=mydb";
String pointValue="pangkunkun,name=pangkun4,address=shanghai age=24\n" +
"pangkunkun,name=pangkun5,address=shanghai age=25\n" +
"pangkunkun,name=pangkun6,address=shanghai age=26";
RestTemplate restTemplate=new RestTemplate();
restTemplate.postForObject(url,pointValue,Object.class);
}
从两个表中获取数据
public void getTest(){
DisplayRestTemplaterestTemplate=new DisplayRestTemplate();
String url="http://localhost:8086/query?pretty=true&q=select * from pkk;select * from pangkunkun&db=mydb";
String points=restTemplate.getForObject(url,String.class);
System.out.println("points:"+points);
}
返回结果:
points:{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "pkk",
"columns": [
"time",
"address",
"age",
"name"
],
"values": [
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
21,
"pangkun1"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
23,
"pangkun3"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
22,
"pangkun2"
]
]
}
]
},
{
"statement_id": 1,
"series": [
{
"name": "pangkunkun",
"columns": [
"time",
"address",
"age",
"name"
],
"values": [
[
"2017-07-28T05:39:53.081302642Z",
"shanghai",
24,
"pangkun4"
],
[
"2017-07-28T05:39:53.081302642Z",
"shanghai",
26,
"pangkun6"
],
[
"2017-07-28T05:39:53.081302642Z",
"shanghai",
25,
"pangkun5"
]
]
}
]
}
]
}
如果是习惯hibernate或者JPA的朋友应该会知道,一般的表联合查询的时候很多都是放到一起:
public void getTest(){
DisplayRestTemplaterestTemplate=new DisplayRestTemplate();
String url="http://localhost:8086/query?pretty=true&q=select * from pkk,pangkunkun&db=mydb";
String points=restTemplate.getForObject(url,String.class);
System.out.println("points:"+points);
}
返回结果:
points:{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "pangkunkun",
"columns": [
"time",
"address",
"age",
"name"
],
"values": [
[
"2017-07-28T05:39:53.081302642Z",
"shanghai",
24,
"pangkun4"
],
[
"2017-07-28T05:39:53.081302642Z",
"shanghai",
26,
"pangkun6"
],
[
"2017-07-28T05:39:53.081302642Z",
"shanghai",
25,
"pangkun5"
]
]
},
{
"name": "pkk",
"columns": [
"time",
"address",
"age",
"name"
],
"values": [
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
21,
"pangkun1"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
23,
"pangkun3"
],
[
"2017-07-28T01:32:03.378554614Z",
"shanghai",
22,
"pangkun2"
]
]
}
]
}
]
}
这个返回的数据是完整的,但是仔细对比会发现跟上边的json结构不同。
第一种两条语句用分号(;)隔开的返回的是两个或多个series(此处只是两条查询,所以是两个),而且statement_id是0和1两个。
第二种两张表之间用逗号隔开的,只返回一个series,所有的结果都在这个series中,而且statement_id的值只有1.
这种情况很好理解,第一种用分号隔开的是两条查询语句,第二种用逗号隔开两张表是一条语句。第二种不需要重写RestTemplate。具体的两种方式的用途也不太相同,各位可以思考下。