You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端提交数据至MySQL出现重复插入行问题求助

问题分析与解决方案:MySQL插入重复行的原因及修复

首先,咱们来拆解你遇到的核心问题:两次HTTP请求触发了两次数据库插入,导致同一用户的数据被分成两行存入数据库。

问题根源拆解

  1. Android端的两次独立请求:你用AsyncHttpClient提交文本数据,又用单独的HttpURLConnection代码上传语音文件,这是两个完全独立的HTTP请求,都会触发PHP脚本里的send()函数。
  2. PHP代码的无差别插入:不管当前请求是文本提交还是语音上传,send()函数都会执行数据库插入操作:
    • 第一次请求(仅文本):没有上传文件,$_FILES['uploaded_file']不存在,$file_path默认变成uploads/,插入后生成第一行数据。
    • 第二次请求(仅语音):虽然上传了文件,但如果请求里附带了重复的文本参数(或者$_REQUEST从URL/表单里拿到了之前的参数),就会再次执行插入,生成第二行数据。

解决方案:合并请求(推荐)

最可靠的方式是把文本数据和语音文件放在同一个Multipart请求里一次性提交,这样PHP只处理一次插入,完美解决重复行问题。

1. 修改Android端代码:用AsyncHttpClient提交Multipart请求

替换原来的两次请求逻辑,把所有数据(文本+语音)打包成一个请求发送:

btn_send.setOnClickListener(v -> {
    // 获取表单输入的文本数据
    String username = "你的用户名"; // 从SharedPreferences或其他地方获取
    String title = new_banners_title.getText().toString().trim();
    String desc = new_banners_desc.getText().toString().trim();
    
    // 检查输入是否为空
    if (title.isEmpty() || desc.isEmpty()) {
        Toast.makeText(this, "标题和描述不能为空", Toast.LENGTH_SHORT).show();
        return;
    }

    // 构建Multipart请求
    AsyncHttpPost post = new AsyncHttpPost(upLoadServerUri);
    MultipartFormDataBody body = new MultipartFormDataBody();
    
    // 添加文本参数
    body.addPart("Username", username);
    body.addPart("Title", title);
    body.addPart("Desc", desc);
    body.addPart("City", city);
    body.addPart("Cate", cate);
    
    // 添加语音文件
    File voiceFile = new File(patch); // patch是你的语音文件本地路径
    if (!voiceFile.exists()) {
        Toast.makeText(this, "语音文件不存在", Toast.LENGTH_SHORT).show();
        return;
    }
    try {
        body.addPart("uploaded_file", voiceFile.getName(), null, new FileInputStream(voiceFile));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        Toast.makeText(this, "读取语音文件失败", Toast.LENGTH_SHORT).show();
        return;
    }

    post.setBody(body);
    
    // 发送请求并处理响应
    AsyncHttpClient.getDefaultInstance().executeString(post, (ex, response) -> {
        runOnUiThread(() -> {
            if (ex == null) {
                String result = response.getString();
                if (result.contains("success") && result.contains("Data inserted successfully")) {
                    Toast.makeText(New_Banners.this, "提交成功!", Toast.LENGTH_SHORT).show();
                    finish();
                } else {
                    Toast.makeText(New_Banners.this, "提交失败:" + result, Toast.LENGTH_SHORT).show();
                }
            } else {
                ex.printStackTrace();
                Toast.makeText(New_Banners.this, "网络连接失败", Toast.LENGTH_SHORT).show();
            }
        });
        return null;
    });
});

2. 修改PHP代码:完善逻辑+防护SQL注入

原代码存在SQL注入风险,且没有做参数校验,修改后的代码如下:

<?php
send();

function connectToDatabase() {
    $connection = mysqli_connect("***", "***", "***", "***");
    if (mysqli_connect_errno()) {
        echo "数据库连接失败: " . mysqli_connect_error();
        exit; // 连接失败直接终止
    }
    mysqli_set_charset($connection, "utf8");
    return $connection;
}

function send() {
    // 校验必填参数是否存在
    $requiredParams = ['Username', 'Title', 'Desc', 'City', 'Cate'];
    foreach ($requiredParams as $param) {
        if (!isset($_REQUEST[$param]) || empty(trim($_REQUEST[$param]))) {
            echo "缺少必填参数: $param";
            return;
        }
    }

    $file_path = "";
    // 处理文件上传(如果有)
    if (isset($_FILES['uploaded_file']) && $_FILES['uploaded_file']['error'] == UPLOAD_ERR_OK) {
        $uploadDir = "uploads/";
        // 确保上传目录存在
        if (!file_exists($uploadDir)) mkdir($uploadDir, 0755, true);
        
        $fileName = basename($_FILES['uploaded_file']['name']);
        // 可以添加文件类型校验,比如只允许mp3等音频格式
        $allowedExts = ['mp3', 'wav', 'm4a'];
        $fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        if (!in_array($fileExt, $allowedExts)) {
            echo "不允许的文件格式";
            return;
        }
        
        $file_path = $uploadDir . $fileName;
        if (!move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $file_path)) {
            echo "文件上传失败";
            return;
        }
        echo "文件上传成功; ";
    }

    // 连接数据库并插入数据(使用预处理语句防SQL注入)
    $connection = connectToDatabase();
    $stmt = mysqli_prepare($connection, 
        "INSERT INTO banners (Username, Title, Descript, City, Cate, Date, voice, Status) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
    );
    
    $username = trim($_REQUEST['Username']);
    $title = trim($_REQUEST['Title']);
    $desc = trim($_REQUEST['Desc']);
    $city = trim($_REQUEST['City']);
    $cate = trim($_REQUEST['Cate']);
    $date = date("Y/m/d G:i");
    $status = 1;

    // 绑定参数
    mysqli_stmt_bind_param($stmt, "sssssssi", $username, $title, $desc, $city, $cate, $date, $file_path, $status);
    
    if (mysqli_stmt_execute($stmt)) {
        echo "数据插入成功";
    } else {
        echo "数据插入失败: " . mysqli_error($connection);
    }

    mysqli_stmt_close($stmt);
    mysqli_close($connection);
}
?>

额外注意事项

  1. SQL注入防护:原代码直接把用户输入拼到SQL里,非常危险,必须用预处理语句(上面的代码已经实现)。
  2. 文件上传安全:添加了文件格式校验,你还可以限制文件大小,避免恶意文件上传。
  3. 错误处理:完善了参数校验、数据库连接错误、文件上传错误的提示,方便排查问题。

内容的提问来源于stack exchange,提问作者alexis programmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:20:55