<think>我们被要求提供使用Spark读写MySQL数据库的方法。根据用户之前的请求,他可能已经了解HBase的读写方法,现在转向关系型数据库MySQL。我们将结合引用内容,特别是引用[1][3][4]中关于MySQL的操作,提供完整的Spark读写MySQL指南。
## Spark读写MySQL数据库方法指南
### 一、环境准备
#### 1.1 添加MySQL驱动依赖
```xml
<!-- Maven依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version> <!-- 版本需与MySQL服务器版本匹配 -->
</dependency>
```
#### 1.2 配置SparkSession
```scala
import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder()
.appName("Spark MySQL Example")
.master("local[*]")
.config("spark.sql.warehouse.dir", "/user/hive/warehouse")
.getOrCreate()
```
### 二、读取MySQL数据
#### 2.1 使用DataFrame API读取(推荐)
```scala
val jdbcDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver") // 驱动类
.load()
jdbcDF.show()
```
#### 2.2 自定义查询读取
```scala
val queryDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("query", "SELECT name, salary FROM employees WHERE salary > 5000")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.load()
```
#### 2.3 分区读取(大数据量优化)
```scala
val partitionedDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.option("numPartitions", 10) // 设置分区数
.option("partitionColumn", "id") // 分区列(必须是整数类型)
.option("lowerBound", 1) // 分区列最小值
.option("upperBound", 100000) // 分区列最大值
.load()
```
### 三、写入MySQL数据
#### 3.1 基础写入方法
```scala
import org.apache.spark.sql.SaveMode
val data = Seq(
("Alice", 28, 8000),
("Bob", 32, 7500)
)
val df = spark.createDataFrame(data).toDF("name", "age", "salary")
df.write
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.mode(SaveMode.Append) // 保存模式:覆盖/追加等
.save()
```
#### 3.2 批量写入优化
```scala
df.write
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.option("batchsize", 10000) // 每批次写入记录数
.mode(SaveMode.Overwrite)
.save()
```
### 四、性能优化技巧
1. **连接池配置**:使用HikariCP等连接池减少连接开销
2. **并行读取**:通过`numPartitions`和`partitionColumn`实现并行读取
3. **写入批处理**:调整`batchsize`参数(默认1000)
4. **数据类型映射**:确保Spark与MySQL数据类型正确匹配
5. **事务隔离级别**:对于写入操作可设置`isolationLevel`参数
### 五、常见问题解决
1. **驱动未找到**:
- 确保驱动jar包在classpath中
- 提交作业时添加`--jars mysql-connector-java-8.0.28.jar`
2. **时区问题**:
```scala
.option("connectionTimeZone", "UTC") // 设置连接时区
```
3. **SSL警告**:
```scala
.option("useSSL", "false") // 测试环境禁用SSL
```
### 六、完整示例(Zeppelin环境)
参考引用[4]中的Zeppelin示例:
```scala
%spark
// 读取数据
val df = spark.read.format("jdbc")
.option("url","jdbc:mysql://192.134.216.130:3306/dw")
.option("dbtable","stu_info")
.option("user","root")
.option("password","123456!a")
.load()
.select("id","name","sex")
.withColumn("id",col("id")+1)
// 写入数据
df.write.format("jdbc")
.option("url","jdbc:mysql://192.134.216.130:3306/dw")
.option("dbtable","stuinfo")
.option("user","root")
.option("password","123456!a")
.mode(SaveMode.Append)
.save()
```
> **注意**:实际应用中需根据MySQL版本选择匹配的驱动版本(MySQL 5.x建议使用5.1.x驱动,MySQL 8.x使用8.0.x驱动)[^3]。
§§相关问题§§
1. 如何解决Spark读取MySQL时的数据类型转换问题?
2. Spark写入MySQL时如何实现幂等操作?
3. 如何监控Spark与MySQL的数据传输性能?
4. Spark SQL如何直接执行MySQL原生查询?
5. 使用Kerberos认证时如何配置Spark连接MySQL?
</think>
# Spark读写MySQL数据库数据指南
下面我将详细介绍Spark读写MySQL数据库的完整方法,涵盖数据读取、写入和性能优化技巧。
## 一、环境准备
### 1.1 添加MySQL驱动依赖
```xml
<!-- Maven依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version> <!-- 版本需与MySQL服务器版本匹配 -->
</dependency>
```
### 1.2 创建SparkSession
```scala
import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder()
.appName("Spark MySQL Example")
.master("local[*]")
.config("spark.sql.warehouse.dir", "/user/hive/warehouse")
.getOrCreate()
```
## 二、读取MySQL数据
### 2.1 基础读取方法
```scala
val jdbcDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver") // 驱动类
.load()
jdbcDF.show()
```
### 2.2 分区读取(大数据量优化)
```scala
val partitionedDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.option("numPartitions", 10) // 设置分区数
.option("partitionColumn", "id") // 分区列(必须是整数类型)
.option("lowerBound", 1) // 分区列最小值
.option("upperBound", 100000) // 分区列最大值
.load()
```
### 2.3 自定义SQL查询
```scala
val queryDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("query", "SELECT name, salary FROM employees WHERE salary > 5000")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.load()
```
## 三、写入MySQL数据
### 3.1 基础写入方法
```scala
import org.apache.spark.sql.SaveMode
val data = Seq(
("Alice", 28, 8000),
("Bob", 32, 7500)
)
val df = spark.createDataFrame(data).toDF("name", "age", "salary")
df.write
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.mode(SaveMode.Append) // 保存模式:覆盖/追加等
.save()
```
### 3.2 批量写入优化
```scala
df.write
.format("jdbc")
.option("url", "jdbc:mysql://localhost:3306/testdb")
.option("dbtable", "employees")
.option("user", "root")
.option("password", "mypassword")
.option("driver", "com.mysql.jdbc.Driver")
.option("batchsize", 10000) // 每批次写入记录数
.mode(SaveMode.Overwrite)
.save()
```
### 3.3 使用Spark SQL写入
```scala
// 注册为临时视图
df.createOrReplaceTempView("temp_employees")
// 使用SQL写入
spark.sql(
s"""
CREATE TABLE employees
USING org.apache.spark.sql.jdbc
OPTIONS (
url 'jdbc:mysql://localhost:3306/testdb',
dbtable 'employees',
user 'root',
password 'mypassword',
driver 'com.mysql.jdbc.Driver'
) AS SELECT * FROM temp_employees
"""
)
```
## 四、性能优化技巧
1. **连接池配置**:使用HikariCP等连接池减少连接开销
2. **并行读取**:通过`numPartitions`和`partitionColumn`实现并行读取
3. **写入批处理**:调整`batchsize`参数(默认1000)
4. **数据类型映射**:确保Spark与MySQL数据类型正确匹配
5. **事务隔离级别**:对于写入操作可设置`isolationLevel`参数
```scala
.option("isolationLevel", "READ_COMMITTED") // 控制事务隔离级别
```
## 五、常见问题解决
1. **驱动未找到**:
- 确保驱动jar包在classpath中
- 提交作业时添加`--jars mysql-connector-java-8.0.28.jar`
2. **时区问题**:
```scala
.option("connectionTimeZone", "UTC") // 设置连接时区
```
3. **SSL警告**:
```scala
.option("useSSL", "false") // 测试环境禁用SSL
```
## 六、完整示例(Zeppelin环境)
参考引用[4]中的Zeppelin示例:
```scala
%spark
// 读取数据
val df = spark.read.format("jdbc")
.option("url","jdbc:mysql://192.134.216.130:3306/dw")
.option("dbtable","stu_info")
.option("user","root")
.option("password","123456!a")
.load()
.select("id","name","sex")
.withColumn("id",col("id")+1)
// 写入数据
df.write.format("jdbc")
.option("url","jdbc:mysql://192.134.216.130:3306/dw")
.option("dbtable","stuinfo")
.option("user","root")
.option("password","123456!a")
.mode(SaveMode.Append)
.save()
```
> **注意**:实际应用中需根据MySQL版本选择匹配的驱动版本(MySQL 5.x建议使用5.1.x驱动,MySQL 8.x使用8.0.x驱动)。