最近使用spark jdbc写关系库数据库 用的是Overwrite模式,发现字段类型被重建为 TEXT。
为了使Spark不修改表原本的类型,我们让Overwrite操作采用truncate table的方式而不是重建表
查看官方文档后看到 truncate 属性
image
在options中设置了truncate属性后 发现仍未解决问题
代码如下:
val options = Map(
"url" -> url,
"driver" -> driverClass,
"user" -> user,
"password" -> password,
"dbtable" -> tableName,
"truncate" -> "true")
df.write.mode(SaveMode.Overwrite).format("jdbc").options(options).save()
查看源码:
image.png
isTruncate就是我们配置的truncate属性了
后面的isCascadingTruncateTable(url) 是判断数据库是否支持truncate操作。
继续看:
image.png
image.png
原来是在这里根据url 来匹配Spark适配的JdbcDialect
而Spark并未适配我们使用的informix数据库 所以truncate属性并不生效
解决方案:
1、适配informix数据库
object InformixDialect extends JdbcDialect {
override def canHandle(url:String):Boolean = url.startsWith("jdbc:informix")
override def isCascadingTruncateTable(): Option[Boolean] =Some(false)
override def getJDBCType(dt: DataType): Option[JdbcType] = dt match {
case StringType =>Option(JdbcType("VARCHAR(128)", java.sql.Types.VARCHAR))
}
}
canHandle: 适配jdbc url
isCascadingTruncateTable: 支持truncate操作,这里需要设置为false 才支持truncat。⊙Д⊙
getJDBCType: 映射jdbcType 和 sqlType 用来支持建表操作
2、注册方言
JdbcDialects.registerDialect(InformixDialect)
3、写库
val options = Map(
"url" -> url,
"driver" -> driverClass,
"user" -> user,
"password" -> password,
"dbtable" -> tableName,
"truncate" -> "true")
df.write.mode(SaveMode.Overwrite).format("jdbc").options(options).save()
成功写入 并不会对表字段产生影响。