问题背景
经过Spark处理之后的数据,需要写到MySQL在web页面进行展示。
遇到的问题
因为考虑到写入MySQL中的字段类型,需要提前在MySQL创建好对应的表。并通过JDBC将DataFrame中的内容写入到MySQL。
最初尝试写入MySQL的代码如下:
val df: Dataframe = ...
df
.coalesce(2)
.write
.mode("overwrite")
.jdbc(url, "rcc.cr_second_credit_report", props)
程序是跑成功了,但是到MySQL里面查看数据,发现之前创建的表结构已经被覆盖了,也不是原来的数据类型,都是DataFrame带过来的数据类型,可以说是一团乱。
之后查找原因,发现是DataFrameWriter在SaveMode.Overwrite 模式下写JDBC时,会有一个选项"truncate",默认值是"false"。在默认值情况下,DataFrame写入MySQL会先drop掉已存在的表,然后再根据要写入的DataFrame信息推断出新的建表语句,并create table。明白了这个,也就不难理解,为什么我们明明已经创建好了表却还是被覆盖掉的原因了。
解决方法
解决方法很简单,就是把选项"truncate"设置为"true"。设置为"true"之后,在通过SaveMode.Overwrite 模式写JDBC时,就会使用"TRUNCATE TABLE"代替"DROP TABLE",也就是只会删除已存在表的数据,并不会删除表结构。
代码如下:
val df: Dataframe = ...
df
.coalesce(2)
.write
.mode("overwrite")
.option("truncate", "true") //设置为true
.jdbc(url, "rcc.cr_second_credit_report", props)
不过也要注意:在不同的DBMS中"TRUNCATE TABLE"的作用也是不相同的,所以使用这样选项也并不总是安全的。MySQLDialect, DB2Dialect, MsSqlServerDialect, DerbyDialect,和OracleDialect是支持这个选项的,而 PostgresDialect和默认的JDBCDirect是不支持的。对于那些未知和不支持的JDBCDirect,如果使用了选项"truncate",将会被忽略,不起作用。