TDengine与springboot集成,TDengine的jdbc的工具

3 篇文章 0 订阅
2 篇文章 0 订阅

TDengine 官方没有windows下的dll库,需要自行编译源码。

在linux下安装之后有现成so库,可以供jdbc的dirver连接需要使用。

TDengine 和springboot集成,如果使用mybaties,查询会出错,没有数据。

但是处理TDengine的数据一般只有新增和查询操作。

代码参见 https://github.com/yz4322gly/TDengineUtil.git

封装代码如下:

package cn.netuo.util;

import com.taosdata.jdbc.TSDBDriver;
import net.sf.cglib.beans.BeanMap;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author guolinyuan
 */
public class TDengineUtil
{
    private Connection connection;
    private boolean databaseColumnHumpToLine;

    /**
     *
     * @param url url 例如 : "jdbc:TAOS://127.0.0.1:6020/netuo_iot"
     * @param username 例如: "root"
     * @param password 例如: "taosdata"
     * @param databaseColumnHumpToLine 是否需要数据库列名下划线转驼峰
     */
    public TDengineUtil(String url, String username, String password, boolean databaseColumnHumpToLine) throws ClassNotFoundException, SQLException
    {
        Class.forName("com.taosdata.jdbc.TSDBDriver");
        String jdbcUrl = url;
        Properties connProps = new Properties();
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_USER, username);
        connProps.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, password);
        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");
        this.connection = DriverManager.getConnection(jdbcUrl, connProps);
        this.databaseColumnHumpToLine = databaseColumnHumpToLine;
    }

    /**
     *
     * @param connection
     * @param databaseColumnHumpToLine
     */
    public TDengineUtil(Connection connection, boolean databaseColumnHumpToLine)
    {
        this.connection = connection;
        this.databaseColumnHumpToLine = databaseColumnHumpToLine;
    }



    /**
     * 执行sql(无论是否返回结果),将结果注入到指定的类型实例中,且返回
     * 当查询到的数据大于一个时,取第一个
     * <p>
     * 对象遵从以下说明<br/>
     * 1.对象字段为String类型,数据库类型(通过jdbc读取到的)无论什么类型,都将调用Object.toString方法注入值<br/>
     * 2.对象字段为数据库类型(通过jdbc读取到的)一致的情况下,将会直接注入<br/>
     * 3.对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试使用{@link Class#cast(Object)}方法转型,失败此值会是类型默认值(故实体推荐使用封装类型)<br/>
     * 4.对象字段为{@link Date}时,数据库类型为Date才可以注入,如果为long(例如TDengine)将会被当作毫秒的时间戳注入<br/>
     *
     * @param sql   要执行的sql
     * @param clazz 要注入的实体类型
     * @param <T>   要注入的实体类型
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws SQLException
     */
    public <T> T getOne(String sql, Class<T> clazz) throws IllegalAccessException, InstantiationException, SQLException
    {
        Method[] setterMethods = getSetterMethods(clazz);
        ResultSet resultSet = connection.createStatement().executeQuery(sql);

        //只有一个结果直接下一个就行
        resultSet.next();

        return resultSetToObject(resultSet, setterMethods, clazz);
    }


    /**
     * 执行sql(无论是否返回结果),将结果注入到指定的类型实例中,且返回
     * 当查询到的结果没有时,返回一个大小为0的list;
     * <p>
     * 对象遵从以下说明<br/>
     * 1.对象字段为String类型,数据库类型(通过jdbc读取到的)无论什么类型,都将调用Object.toString方法注入值<br/>
     * 2.对象字段为数据库类型(通过jdbc读取到的)一致的情况下,将会直接注入<br/>
     * 3.对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试使用{@link Class#cast(Object)}方法转型,失败此值会是类型默认值(故实体推荐使用封装类型)<br/>
     * 4.对象字段为{@link Date}时,数据库类型为Date才可以注入,如果为long(例如TDengine)将会被当作毫秒的时间戳注入<br/>
     *
     * @param sql   要执行的sql
     * @param clazz 要注入的实体类型
     * @param <T>   要注入的实体类型
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws SQLException
     */
    public <T> List<T> getList(String sql, Class<T> clazz) throws IllegalAccessException, InstantiationException, SQLException
    {
        List<T> list = new ArrayList<>();

        Method[] setterMethods = getSetterMethods(clazz);
        ResultSet resultSet = connection.createStatement().executeQuery(sql);

        while (resultSet.next())
        {
            list.add(resultSetToObject(resultSet, setterMethods, clazz));
        }
        return list;
    }

    /**
     * 插入对象到指定的表里面
     * @param tableName
     * @param o
     * @return
     * @throws SQLException
     */
    @SuppressWarnings("all")
    public boolean insert(String tableName,Object o) throws SQLException
    {
        Class clazz = o.getClass();
        Map<String,Object> map = BeanMap.create(o);

        String sql = createInsertSql(tableName,map);
        return connection.createStatement().execute(sql);
    }

    /**
     * 生成插入sql语句
     * @param tableName
     * @param map
     * @return
     */
    public static String createInsertSql(String tableName,Map<String,Object> map)
    {
        StringBuilder buffer = new StringBuilder();
        buffer.append("INSERT INTO ").append(tableName).append(" (");

        Set<Map.Entry<String,Object>> set = map.entrySet();

        StringBuilder keys = new StringBuilder(" ");
        StringBuilder value = new StringBuilder(" ");

        for (Map.Entry<String,Object> entry : set)
        {
            keys.append(humpToLine(entry.getKey())).append(",");
            try
            {
                if (entry.getValue().getClass().equals(Date.class))
                {
                    Date d = (Date)entry.getValue();
                    value.append(d.getTime()).append(",");
                }
                else
                {
                    value.append("'").append(entry.getValue()).append("'").append(",");
                }
            }
            catch (Exception ignored)
            {

            }
        }

        keys.deleteCharAt(keys.length()-1);
        value.deleteCharAt(value.length()-1);

        buffer.append(keys).append(") VALUES( ").append(value).append(")");

        return buffer.toString();
    }


    /**
     * 将resultSet注入到指定的类型实例中,且返回
     * 对象遵从以下说明<br/>
     * 1.对象字段为String类型,数据库类型(通过jdbc读取到的)无论什么类型,都将调用Object.toString方法注入值<br/>
     * 2.对象字段为数据库类型(通过jdbc读取到的)一致的情况下,将会直接注入<br/>
     * 3.对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试使用{@link Class#cast(Object)}方法转型,失败此值会是类型默认值(故实体推荐使用封装类型)<br/>
     * 4.对象字段为{@link Date}时,数据库类型为Date才可以注入,如果为long(例如TDengine)将会被当作毫秒的时间戳注入<br/>
     * <p>
     * 注意,此方法只会注入一个结果,不会循环{@link ResultSet#next()}方法,请从外部调用。<br/>
     * 传入setterMethods的目的是为了方便外部循环使用此方法,这样方法内部不会重复调用,提高效率<br/>
     *
     * @param resultSet     查询结果,一定要是{@link ResultSet#next()}操作过的,不然没有数据
     * @param setterMethods clazz对应的所有setter方法,可以使用{@link this#getSetterMethods(Class)}获取
     * @param clazz         注入对象类型
     * @param <T>           注入对象类型
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public <T> T resultSetToObject(ResultSet resultSet, Method[] setterMethods, Class<T> clazz) throws IllegalAccessException, InstantiationException
    {
        T result;
        try
        {
            result = clazz.newInstance();
        }
        catch (InstantiationException e)
        {
            System.out.println("请检查类" + clazz.getCanonicalName() + "是否有无参构造方法");
            throw e;
        }


        for (Method method : setterMethods)
        {
            try
            {
                String fieldName = getFieldNameBySetter(method);

                //因为标准的setter方法只会有一个参数,所以取一个就行了
                Class getParamClass = method.getParameterTypes()[0];



                //获得查询的结果
                Object resultObject;

                //是否启用驼峰转下划线规则获得数据库字段名
                if (databaseColumnHumpToLine)
                {
                    resultObject = resultSet.getObject(humpToLine(fieldName));
                }
                else
                {
                    resultObject = resultSet.getObject(fieldName);
                }

                //如果实体类的类型是String类型,那么无论x数据库类型是什么,都调用其toString方法获取值
                if (getParamClass.equals(String.class))
                {
                    method.invoke(result, resultObject.toString());
                }
                else if (getParamClass.equals(Date.class) && resultObject.getClass().equals(Long.class))
                {
                    method.invoke(result, new Date((Long) resultObject));
                }
                else
                {
                    try
                    {
                        method.invoke(result, resultObject);
                    }
                    catch (IllegalArgumentException e)
                    {
                        //对象字段与数据库类型(通过jdbc读取到的)不一致的情况下,将尝试强制转型
                        method.invoke(result, getParamClass.cast(resultObject));
                    }
                }
            }
            catch (Exception ignored)
            {
                //所有的转型都失败了,则使用默认值
            }
        }

        return result;
    }

    /**
     * 通过setter method,获取到其对应的属性名
     *
     * @param method
     * @return
     */
    public static String getFieldNameBySetter(Method method)
    {
        return toLowerCaseFirstOne(method.getName().substring(3));
    }


    /**
     * 获取指定类型方法的所有的setter方法
     * 方法属性名为key,对应的方法为value
     *
     * @param clazz
     * @return
     */
    public static Map<String, Method> getSetterMethodsMap(Class clazz)
    {
        Method[] methods = clazz.getMethods();
        Map<String, Method> setterMethods = new HashMap<>(methods.length / 2);

        for (Method m : methods)
        {
            if (m.getName().startsWith("set"))
            {
                setterMethods.put(toLowerCaseFirstOne(m.getName().substring(3)), m);
            }
        }
        return setterMethods;
    }

    /**
     * 获取指定类型方法的所有的setter方法
     *
     * @param clazz
     * @return
     */
    public static Method[] getSetterMethods(Class clazz)
    {
        Method[] methods = clazz.getMethods();
        Method[] setterMethods = new Method[methods.length / 2];

        int i = 0;
        for (Method m : methods)
        {
            if (m.getName().startsWith("set"))
            {
                setterMethods[i] = m;
                i++;
            }
        }
        return setterMethods;
    }

    /**
     * 首字母转小写
     */
    public static String toLowerCaseFirstOne(String s)
    {
        if (Character.isLowerCase(s.charAt(0)))
        {
            return s;
        }
        else
        {
            return Character.toLowerCase(s.charAt(0)) + s.substring(1);
        }
    }


    /**
     * 首字母转大写
     */
    public static String toUpperCaseFirstOne(String s)
    {
        if (Character.isUpperCase(s.charAt(0)))
        {
            return s;
        }
        else
        {
            return Character.toUpperCase(s.charAt(0)) + s.substring(1);
        }
    }

    private static Pattern linePattern = Pattern.compile("_(\\w)");

    /** 下划线转驼峰 */
    public static String lineToHump(String str) {
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    private static Pattern humpPattern = Pattern.compile("[A-Z]");

    /**
     * 驼峰转下划线,效率比上面高
     */
    public static String humpToLine(String str)
    {
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find())
        {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
}

实例代码如下

package cn.netuo.util;

import java.util.List;


public class Main
{
    public static void main(String[] args) throws Exception
    {
        TDengineUtil util = new TDengineUtil("jdbc:TAOS://127.0.0.1:6020/netuo_iot","root","taosdata",true);

//        util.insert("v1_001",new cn.netuo.util.IotReceiptUploadDataEntity(new Date(),null,"33.3",true,"12","1234",12,"22.3","30","14",new Date()));
        List<IotReceiptUploadDataEntity> list = util.getList("select * from  v1_001",IotReceiptUploadDataEntity.class);
        System.out.println(list);
    }
}

实体类如下

package cn.netuo.util;

import java.util.Date;

/**
 * @author guolinyuan
 */
public class IotReceiptUploadDataEntity
{

    /**
     * lng : 经纬度
     * lat : 经纬度
     * isCharging : 电池是否在充电
     * battery : 电池电量
     * workingTime : 连续开机时间
     * ei : 业务电流(A)
     * ep : 业务功率(W)
     * tmp : 温度
     * humidity : 湿度
     * downtime : 上次停机时间,时间戳,精确到毫秒的(本文时间戳均为精确到毫秒的)
     */
    private Date ts;
    private String lng;
    private String lat;
    private Boolean isCharging;
    private String battery;
    private String workingTime;
    private Integer ei;
    private String ep;
    private String tmp;
    private String humidity;
    private Date downtime;

    public IotReceiptUploadDataEntity()
    {
    }

    public IotReceiptUploadDataEntity(Date ts, String lng, String lat, Boolean isCharging, String battery, String workingTime, Integer ei, String ep, String tmp, String humidity, Date downtime)
    {
        this.ts = ts;
        this.lng = lng;
        this.lat = lat;
        this.isCharging = isCharging;
        this.battery = battery;
        this.workingTime = workingTime;
        this.ei = ei;
        this.ep = ep;
        this.tmp = tmp;
        this.humidity = humidity;
        this.downtime = downtime;
    }

    public void setEi(Integer ei)
    {
        this.ei = ei;
    }

    public Date getTs()
    {
        return ts;
    }

    public void setTs(Date ts)
    {
        this.ts = ts;
    }

    public String getLng()
    {
        return lng;
    }

    public void setLng(String lng)
    {
        this.lng = lng;
    }

    public String getLat()
    {
        return lat;
    }

    public void setLat(String lat)
    {
        this.lat = lat;
    }

    public Boolean getIsCharging()
    {
        return isCharging;
    }

    public void setIsCharging(Boolean isCharging)
    {
        this.isCharging = isCharging;
    }

    public String getBattery()
    {
        return battery;
    }

    public void setBattery(String battery)
    {
        this.battery = battery;
    }

    public String getWorkingTime()
    {
        return workingTime;
    }

    public void setWorkingTime(String workingTime)
    {
        this.workingTime = workingTime;
    }


    public String getEp()
    {
        return ep;
    }

    public void setEp(String ep)
    {
        this.ep = ep;
    }

    public String getTmp()
    {
        return tmp;
    }

    public void setTmp(String tmp)
    {
        this.tmp = tmp;
    }

    public String getHumidity()
    {
        return humidity;
    }

    public void setHumidity(String humidity)
    {
        this.humidity = humidity;
    }

    public Date getDowntime()
    {
        return downtime;
    }

    public void setDowntime(Date downtime)
    {
        this.downtime = downtime;
    }

    @Override
    public String toString()
    {
        return "cn.netuo.util.IotReceiptUploadDataEntity{" +
                "ts=" + ts +
                ", lng='" + lng + '\'' +
                ", lat='" + lat + '\'' +
                ", isCharging='" + isCharging + '\'' +
                ", battery='" + battery + '\'' +
                ", workingTime='" + workingTime + '\'' +
                ", ei='" + ei + '\'' +
                ", ep='" + ep + '\'' +
                ", tmp='" + tmp + '\'' +
                ", humidity='" + humidity + '\'' +
                ", downtime='" + downtime + '\'' +
                '}';
    }
}

 

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
要将ClickHouse-JDBC集成到Spring Boot项目中,可以按照以下步骤进行操作: 1. 在`pom.xml`文件中添加ClickHouse-JDBC依赖: ```xml <dependency> <groupId>ru.yandex.clickhouse</groupId> <artifactId>clickhouse-jdbc</artifactId> <version>0.3.1</version> </dependency> ``` 2. 在`application.properties`文件中配置ClickHouse连接信息: ```properties spring.datasource.url=jdbc:clickhouse://localhost:8123/database_name spring.datasource.username=your_username spring.datasource.password=your_password ``` 3. 创建一个ClickHouse配置类,用于配置ClickHouse连接池和连接工厂: ```java @Configuration public class ClickHouseConfig { @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Bean public DataSource clickHouseDataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl(url); config.setUsername(username); config.setPassword(password); return new HikariDataSource(config); } @Bean public JdbcTemplate clickHouseJdbcTemplate(DataSource clickHouseDataSource) { return new JdbcTemplate(clickHouseDataSource); } } ``` 4. 在需要使用ClickHouse的地方注入`JdbcTemplate`实例,并使用它执行查询: ```java @Service public class MyService { private final JdbcTemplate clickHouseJdbcTemplate; public MyService(JdbcTemplate clickHouseJdbcTemplate) { this.clickHouseJdbcTemplate = clickHouseJdbcTemplate; } public List<Map<String, Object>> executeQuery(String sql) { return clickHouseJdbcTemplate.queryForList(sql); } } ``` 以上就是在Spring Boot项目中集成ClickHouse-JDBC的基本步骤。你可以根据自己的需求进行适当的调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值