凌峰创科服务平台

Android如何连接MySQL服务器?

核心问题:为什么不能直接在 Android 上连接 MySQL?

在开始之前,最重要的一点是理解:Android App(客户端)不应该也不应该直接连接到公网上的 MySQL 数据库。

Android如何连接MySQL服务器?-图1
(图片来源网络,侵删)

原因如下:

  1. 安全风险(最主要的原因)

    • 数据库凭据暴露:如果将数据库的用户名、密码、IP地址、端口等直接写在 App 的代码里(即使是加密的),一旦 App 被反编译,这些信息就完全暴露了,攻击者可以轻易地获取你的数据库凭据,从而窃取、篡改甚至删除你的所有数据。
    • SQL 注入:客户端直接连接数据库,很难完全防止 SQL 注入攻击,这会严重威胁数据安全。
  2. 网络架构问题

    • 公网 IP 和端口:大多数数据库服务器没有公网 IP,或者防火墙不允许 3306 (MySQL 默认端口) 这样的端口对外访问。
    • NAT 和防火墙:手机和服务器通常都位于 NAT(网络地址转换)之后,直接建立连接非常困难且不稳定。
  3. 性能和可维护性

    Android如何连接MySQL服务器?-图2
    (图片来源网络,侵删)
    • 连接管理:每个 App 连接都是一个数据库连接,如果用户量巨大,数据库服务器会因连接数耗尽而崩溃。
    • 业务逻辑耦合:如果数据库表结构需要修改,你就必须强制所有用户更新 App,这在实际开发中是不可行的。
    • 不灵活:数据库迁移、扩容、读写分离等后端操作会直接影响 App 的稳定性。

推荐架构:客户端 -> 服务器 -> 数据库

正确的做法是引入一个中间层,也就是后端服务器,架构如下:

[Android App]  <--(HTTPS/JSON/XML)-->  [Your Backend Server]  <--(Internal Network)-->  [MySQL Database]

工作流程:

  1. Android App 作为客户端,负责用户界面和交互。
  2. App 不直接连接 MySQL,而是通过 HTTP/HTTPS 协议向后端服务器发送请求GET /api/users/123)。
  3. 后端服务器(例如用 Java Spring Boot, Node.js, Python Flask/Django 等编写)接收这个请求。
  4. 后端服务器验证请求的合法性(例如检查用户 Token 是否有效)。
  5. 服务器使用 JDBC (Java) 或其他数据库驱动,安全地连接到本地或内网的 MySQL 数据库。
  6. 服务器执行数据库操作(查询、增、删、改),然后将结果打包成 JSON 或 XML 格式。
  7. 服务器将 JSON/XML 数据通过 HTTP 响应返回给 Android App。
  8. Android App 解析收到的 JSON/XML 数据,并更新 UI。

这种架构的优势:

  • 安全:数据库凭据只存在于服务器上,App 完全接触不到,服务器可以处理所有认证和授权。
  • 灵活:后端 API 可以独立于 App 进行迭代,你可以修改数据库逻辑或增减接口,而无需更新 App(只要 API 格式不变)。
  • 可扩展:当用户量增长时,你可以轻松地扩展后端服务器集群,而数据库只需连接到这些服务器即可。
  • 解耦:客户端和服务器是分离的,可以由不同的团队使用不同的技术栈进行开发。

如何实现:后端服务器部分(以 Java Spring Boot 为例)

这是连接 MySQL 的核心部分。

Android如何连接MySQL服务器?-图3
(图片来源网络,侵删)

项目准备

  • 使用 Spring Initializr (https://start.spring.io/) 创建一个新项目。
  • 添加依赖:
    • Spring Web:用于创建 RESTful API。
    • Spring Data JPA:简化数据库操作。
    • MySQL Driver:Java 连接 MySQL 的驱动。
    • Lombok (可选):简化代码。

配置 application.properties

src/main/resources/application.properties 文件中配置数据库连接信息。

# 服务器端口
server.port=8080
# MySQL 数据库配置
# 注意:这里的 username 和 password 是你数据库的用户名和密码
spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name?useSSL=false&serverTimezone=UTC
spring.datasource.username=your_db_user
spring.datasource.password=your_db_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA (Hibernate) 配置
# 自动更新数据库表结构(开发环境可用,生产环境建议手动管理)
spring.jpa.hibernate.ddl-auto=update
# 显示 SQL 语句
spring.jpa.show-sql=true
# 格式化 SQL 语句
spring.jpa.properties.hibernate.format_sql=true

创建实体类

import jakarta.persistence.*;
@Entity // 声明这是一个与数据库表对应的实体
@Table(name = "users") // 对应数据库中的 users 表
public class User {
    @Id // 声明为主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主键
    private Long id;
    private String name;
    private String email;
    // Getters and Setters (可以用 Lombok 的 @Data 注解自动生成)
    // ...
}

创建数据访问层

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // Spring Data JPA 会自动实现基本的 CRUD 操作
    // 你也可以在这里定义自定义查询方法,
    // User findByName(String name);
}

创建服务层

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    public User createUser(User user) {
        return userRepository.save(user);
    }
    // ... 其他增删改查方法
}

创建控制器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users") // 定义 API 的基础路径
public class UserController {
    @Autowired
    private UserService userService;
    // GET /api/users -> 获取所有用户
    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
    // GET /api/users/1 -> 根据 ID 获取单个用户
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    // POST /api/users -> 创建一个新用户
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
    // ... 其他接口 (PUT, DELETE)
}

你的后端服务器就准备好了,启动它,访问 http://localhost:8080/api/users 就能测试你的 API。


如何实现:Android 客户端部分

Android 客户端的工作就是通过网络调用上面创建的 API。

添加网络权限

app/src/main/AndroidManifest.xml 中添加:

<uses-permission android:name="android.permission.INTERNET" />

添加网络依赖

app/build.gradle.kts (或 app/build.gradle) 文件中添加 Retrofit 和 Gson 依赖。

// build.gradle.kts
dependencies {
    // ... 其他依赖
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0") // 用于 JSON 转换
    implementation("com.squareup.okhttp3:logging-interceptor:4.11.0") // 用于日志
}

创建数据模型 (与服务器 JSON 对应)

// User.kt
data class User(
    val id: Long,
    val name: String,
    val email: String
)

创建 Retrofit API 接口

// ApiService.kt
import retrofit2.Call
import retrofit2.http.*
interface ApiService {
    // 注意:这里使用服务器的公网 IP 或域名
    @GET("api/users")
    fun getAllUsers(): Call<List<User>>
    @GET("api/users/{id}")
    fun getUserById(@Path("id") id: Long): Call<User>
    @POST("api/users")
    fun createUser(@Body user: User): Call<User>
}

创建 Retrofit 实例

// RetrofitClient.kt
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
    private const val BASE_URL = "http://YOUR_SERVER_IP:8080/" // 替换成你的服务器 IP
    val instance: ApiService by lazy {
        // 创建一个 OkHttp 客户端用于打印日志
        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY
        val okHttpClient = OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .build()
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()
        retrofit.create(ApiService::class.java)
    }
}

重要提示:将 YOUR_SERVER_IP 替换为你的服务器的公网 IP 地址,如果你的服务器和你的电脑在同一个局域网内,你可以用电脑的局域网 IP(如 http://192.168.1.10:8080/)进行测试,但要发布到公网,服务器必须有公网 IP。

在 Activity 或 ViewModel 中调用 API

// MainActivity.kt
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val tvResult: TextView = findViewById(R.id.tv_result)
        val btnFetch: Button = findViewById(R.id.btn_fetch)
        btnFetch.setOnClickListener {
            fetchUsers()
        }
    }
    private fun fetchUsers() {
        val call = RetrofitClient.instance.getAllUsers()
        call.enqueue(object : Callback<List<User>> {
            override fun onResponse(call: Call<List<User>>, response: Response<List<User>>) {
                if (response.isSuccessful) {
                    val userList = response.body()
                    val result = userList?.joinToString(separator = "\n") { "ID: ${it.id}, Name: ${it.name}" }
                    Log.d("API_SUCCESS", "Users: $userList")
                    // 在 UI 线程更新视图
                    runOnUiThread {
                        findViewById<TextView>(R.id.tv_result).text = result ?: "No users found"
                    }
                } else {
                    Log.e("API_ERROR", "Response not successful: ${response.code()}")
                }
            }
            override fun onFailure(call: Call<List<User>>, t: Throwable) {
                Log.e("API_FAILURE", "Failed to fetch users: ${t.message}")
            }
        })
    }
}

部署你的后端服务器

要让 Android App 能在任意地方访问,你需要将后端服务器部署到公网上。

  1. 购买云服务器:例如阿里云、腾讯云、AWS、DigitalOcean、Vultr 等,选择一个配置较低的服务器即可开始。
  2. 安装环境:在服务器上安装 Java (JDK) 和 MySQL。
  3. 配置安全组:在云服务器的管理控制台,找到“安全组”或“防火墙”规则,开放 8080 端口(或你设置的 HTTP 端口),并限制访问来源(建议只允许你的 IP 访问,或者全部开放 0.0.0/0)。
  4. 上传并运行:将你的 Spring Boot 项目打包成 .jar 文件,上传到服务器,然后用 java -jar your-app-name.jar 命令运行。
  5. 使用反向代理(推荐):生产环境中,建议使用 Nginx 作为反向代理,它可以将 80 (HTTP) 或 443 (HTTPS) 端口的请求转发到你应用的 8080 端口,并可以处理 SSL 证书,实现 HTTPS 访问,这是更安全、更专业的做法。

总结与最佳实践

  1. 永远不要让 App 直连 MySQL,这是架构设计的铁律。
  2. 采用 RESTful API 架构,使用 JSON 作为数据交换格式。
  3. 后端首选 Java Spring Boot,它与 Android 开发语言一致,生态成熟,上手快。
  4. Android 客户端使用 Retrofit 进行网络请求,它是目前最流行、最强大的网络库之一。
  5. 服务器必须部署在公网,并配置好防火墙规则。
  6. 生产环境必须使用 HTTPS,以保护数据在传输过程中的安全。
  7. 处理异步操作:网络请求是耗时操作,必须在 Android 的后台线程(如 Coroutine, RxJava, AsyncTask)中执行,并在主线程更新 UI。
  8. 错误处理:妥善处理网络错误、服务器错误和数据解析错误,并向用户友好的提示。

遵循以上步骤和原则,你就可以构建一个安全、可扩展且易于维护的 Android 应用后端系统。

分享:
扫描分享到社交APP
上一篇
下一篇