問題背景
經過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",將會被忽略,不起作用。