从MSSQL导入BigQuery时Dataflow类型转换报错求助
我尝试通过Dataflow的JDBC to BigQuery默认模板,将SQL Server数据库中的一张表导入至BigQuery。该表包含Datetime列,我将其映射为BigQuery的DATETIME类型,连接字符串为:jdbc:sqlserver://<hostIP>:1433;instanceName=SQLSERVER;databaseName=<dbName>;encrypt=true;trustServerCertificate=true;
并已在作业参数中配置账号密码。但Dataflow抛出如下错误:
Error message from worker: java.lang.ClassCastException: class java.sql.Timestamp cannot be cast to class java.time.temporal.TemporalAccessor (java.sql.Timestamp is in module java.sql of loader 'platform'; java.time.temporal.TemporalAccessor is in module java.base of loader 'bootstrap')
com.google.cloud.teleport.templates.common.JdbcConverters$ResultSetToTableRow.mapRow(JdbcConverters.java:157)
com.google.cloud.teleport.templates.common.JdbcConverters$ResultSetToTableRow.mapRow(JdbcConverters.java:115)
com.google.cloud.teleport.io.DynamicJdbcIO$DynamicReadFn.processElement(DynamicJdbcIO.java:388)
我也曾尝试将该列映射为BigQuery的TIMESTAMP类型,仍出现相同错误。排除连接问题,因为仅读取非Datetime列时作业可正常运行。使用的JDBC驱动为com.microsoft.sqlserver.jdbc.SQLServerDriver,版本为Maven下载的mssql-jdbc-11.2.1.jre8.jar。
问题原因
- Dataflow的JDBC to BigQuery默认模板(
JdbcConverters类)在处理日期时间类型时,默认假设JDBC驱动返回的是java.time.temporal.TemporalAccessor接口的实现类(如Java 8+的LocalDateTime),但你使用的SQL Server JDBC驱动针对SQL Server的datetime类型,返回的是传统的java.sql.Timestamp对象,该类并未实现TemporalAccessor接口,直接强制类型转换导致报错。 - 模板代码未兼容旧版日期时间类型的处理逻辑,没有考虑到SQL Server JDBC驱动对
datetime类型的返回特性。
解决方法
方法1:修改JDBC连接参数
在JDBC连接字符串中添加sendTimeAsDatetime=false参数,强制SQL Server JDBC驱动将datetime类型以java.time.LocalDateTime(实现了TemporalAccessor)的形式返回,而非java.sql.Timestamp。修改后的连接字符串如下:jdbc:sqlserver://<hostIP>:1433;instanceName=SQLSERVER;databaseName=<dbName>;encrypt=true;trustServerCertificate=true;sendTimeAsDatetime=false;
方法2:自定义Dataflow模板修改转换逻辑
若无法修改连接参数,需自定义模板代码,在JdbcConverters.java的mapRow方法中添加对java.sql.Timestamp的兼容处理:
- 检查从ResultSet获取的对象类型,若为
Timestamp则转换为LocalDateTime - 再用转换后的对象执行后续的BigQuery字段构建逻辑
示例修改片段:
// 在处理日期时间列的位置添加类型判断与转换 Object value = resultSet.getObject(columnName); if (value instanceof Timestamp) { value = ((Timestamp) value).toLocalDateTime(); } // 原有的类型转换逻辑 TemporalAccessor temporal = (TemporalAccessor) value; // 后续BigQuery DATETIME/TIMESTAMP字段构建代码
方法3:修改源表字段类型
若可以调整SQL Server源表结构,将datetime列改为datetime2类型。SQL Server JDBC驱动对datetime2类型默认返回java.time.LocalDateTime,可直接兼容模板的类型转换逻辑。
内容的提问来源于stack exchange,提问作者alex-mont

