Azure Databricks JDBC连接含特殊字符密码的转义问题问询
问题:Azure Databricks传递含特殊标点的密码导致JDBC连接失败
通过Azure Data Factory调用Databricks,用widget传递包含大量标点符号的密码,变量传递环节正常,但在通过SQL临时视图写入Azure SQL时,因密码中的特殊字符导致解析失败。
原Python代码:
%python #Get variables to write to DB input_sql_conn_string = dbutils.widgets.get("dest_sql_server_url") input_db_name = dbutils.widgets.get("dest_db_name") input_dest_username = dbutils.widgets.get("dest_username") input_dest_password = dbutils.widgets.get("dest_password") input_dest_table_schema = dbutils.widgets.get("dest_table_schema") input_dest_table_name = dbutils.widgets.get("dest_table_name") dest_table_full = input_dest_table_schema + "." + input_dest_table_name #Configure whole connection string url = f"jdbc:sqlserver://{input_sql_conn_string}:1433;database={input_db_name};user={input_dest_username};password={input_dest_password}" #Set conf variables so they are accessible by SQL code spark.conf.set("var.python_sql_url", url) spark.conf.set("var.python_dest_table", dest_table_full) spark.conf.set("var.python_username", input_dest_username) spark.conf.set("var.python_password", input_dest_password)
原SQL代码:
CREATE TEMPORARY VIEW jdbcTable USING org.apache.spark.sql.jdbc OPTIONS ( url ${var.python_sql_url}, dbtable ${var.python_dest_table}, user ${var.python_username}, password ${var.python_password} ); INSERT INTO TABLE jdbcTable SELECT m.eventId, m.locationId, m.occurredOn, m.sequenceNumber, m.eventType FROM unified.events.location m
解决方法
方法1:拆分JDBC配置项,避免拼接完整URL
直接拼接URL时,密码中的分号、等号等特殊字符会破坏JDBC URL格式,改为单独传递各个配置项,让Spark自行处理拼接逻辑:
修改Python代码:
%python # 获取变量 input_sql_conn_string = dbutils.widgets.get("dest_sql_server_url") input_db_name = dbutils.widgets.get("dest_db_name") input_dest_username = dbutils.widgets.get("dest_username") input_dest_password = dbutils.widgets.get("dest_password") input_dest_table_schema = dbutils.widgets.get("dest_table_schema") input_dest_table_name = dbutils.widgets.get("dest_table_name") dest_table_full = f"{input_dest_table_schema}.{input_dest_table_name}" # 设置单个配置项,而非完整URL spark.conf.set("var.sql_server", input_sql_conn_string) spark.conf.set("var.db_name", input_db_name) spark.conf.set("var.dest_username", input_dest_username) spark.conf.set("var.dest_password", input_dest_password) spark.conf.set("var.dest_table_full", dest_table_full)
对应的SQL代码:
CREATE TEMPORARY VIEW jdbcTable USING org.apache.spark.sql.jdbc OPTIONS ( url "jdbc:sqlserver://${var.sql_server}:1433;database=${var.db_name}", dbtable ${var.dest_table_full}, user ${var.dest_username}, password ${var.dest_password} ); INSERT INTO TABLE jdbcTable SELECT m.eventId, m.locationId, m.occurredOn, m.sequenceNumber, m.eventType FROM unified.events.location m
方法2:对密码进行URL编码
使用Python的urllib.parse.quote_plus对密码进行URL编码,转义所有特殊字符,确保拼接后的URL格式合法:
修改Python代码中的URL拼接部分:
%python import urllib.parse # 获取变量(其余代码同原逻辑) input_dest_password = dbutils.widgets.get("dest_password") # 对密码进行URL编码 encoded_password = urllib.parse.quote_plus(input_dest_password) # 拼接URL时使用编码后的密码 url = f"jdbc:sqlserver://{input_sql_conn_string}:1433;database={input_db_name};user={input_dest_username};password={encoded_password}" # 后续设置conf变量代码不变 spark.conf.set("var.python_sql_url", url) # ...其他配置项设置
SQL代码无需修改,保持原逻辑即可。
方法3:直接用Python写入数据(绕开SQL视图)
跳过SQL临时视图环节,直接在Python中读取数据并写入Azure SQL,避免变量跨语言传递时的解析问题:
%python import urllib.parse # 获取变量 input_sql_conn_string = dbutils.widgets.get("dest_sql_server_url") input_db_name = dbutils.widgets.get("dest_db_name") input_dest_username = dbutils.widgets.get("dest_username") input_dest_password = dbutils.widgets.get("dest_password") input_dest_table_schema = dbutils.widgets.get("dest_table_schema") input_dest_table_name = dbutils.widgets.get("dest_table_name") dest_table_full = f"{input_dest_table_schema}.{input_dest_table_name}" # 编码密码并拼接URL encoded_password = urllib.parse.quote_plus(input_dest_password) url = f"jdbc:sqlserver://{input_sql_conn_string}:1433;database={input_db_name};user={input_dest_username};password={encoded_password}" # 读取数据并写入 df = spark.sql("SELECT m.eventId, m.locationId, m.occurredOn, m.sequenceNumber, m.eventType FROM unified.events.location m") df.write \ .format("jdbc") \ .option("url", url) \ .option("dbtable", dest_table_full) \ .option("user", input_dest_username) \ .option("password", input_dest_password) \ .mode("append") # 根据需求选择模式:append/overwrite等 .save()
内容的提问来源于stack exchange,提问作者blobbles
相关产品推荐
相关产品推荐

