【Unity 导出 WebGL 通过Linux宝塔的 Nginx 连接数据库】使用 UnityWebRequest 与 WebAPI (php服务) 执行mysql命令

前言

  • 做项目,需要 Unity 导出的 WebGL 项目能进行与数据库交互,这里指能实现 insert 命令即成功
    项目已经成功部署在 腾讯云服务器下,通过 Linux 宝塔的 Nginx 部署。
  • 于是通过 chatGPT 紧急学习了其他相关技术,来实现与数据库交互的功能。

方案一,MySql.Data.MySqlClient

前置准备

  • 第一种方案比较简单,在 C# 代码直接导入
using System.Data;
using MySql.Data.MySqlClient;

第一个头文件在比较新的Unity Editor版本可自动直接导入,否则需要到具体的编辑器的路径处查找
编辑器的路径可以在UnityHub直接打开
在这里插入图片描述
在这里插入图片描述

  • 头文件,需要在 Plugins 文件夹放置如下 DLL 文件
MySql.Data.dll
I18N.CJK.dll
I18N.dll
I18N.West.dll

其中 MySql.Data.dll这里下载,这里选择第三个版本下载才成功。
后面的四个文件一般在这些目录中:
在这里插入图片描述

  • 然后,上述dll放入该文件夹下。常识性操作。
    在这里插入图片描述

数据库部分

  • Linux 宝塔的该位置添加数据库
    注意编码的区别
    utf8mb4utf8 的基础上支持 most bytes 4,即那些emoji的编码
    utf8 支持全国各种字符,包括中文
    gbk 更加支持中文编码,其中 gbk2312 只支持中文
    注意我们这里选择 utf8 否则后续会需要调整编码,比较麻烦。
  • 记住这里的数据库名,用户名和密码。注意该账号和 root 账号密码之间是不同的。
    在这里插入图片描述
  • 然后在 Navicat 处,连接该数据库,并创建自己需要的表格。
    可能第一次创建时连接失败或者其他别的什么问题,需要下面修改一下:
    修改访问权限
    在这里插入图片描述
    数据库定时备份
    在这里插入图片描述
    放行端口:默认数据库使用 3306 号端口。需要在 Linux 宝塔以及腾讯云服务器处放行。
    在这里插入图片描述
  • 端口号在这里查看。
    在这里插入图片描述

代码部分

  • 代码部分很简单。引入必要的头文件后,在某个类中声明一个 MySqlConnection 连接变量,然后调用 ConnectSQL() 代码,给定数据库名,端口号,用户名和密码然后连接。
    QuerySet() 代码调用,执行 sqlString 命令
	using System.Data;
	using MySql.Data.MySqlClient;
	
    public static string dbName = "XXdb";
    public static string tableName = "XXT";
    public static string host = "IP";
    public static string uname = "aniDB";
    public static string psw = "your password";
    public static string port = "your port";
	private static MySqlConnection con;
	
    public void ConnectSQL()	// 直接复制粘贴使用即可
    {
    
    
        try
        {
    
    
            string mySqlString = string.Format("Database={0};Data Source={1};User Id={2};Password={3};port={4}"
                , dbName, host, uname, psw, port);
            con = new MySqlConnection(mySqlString);
            con.Open();
        }
        catch (Exception e)
        {
    
    
            throw new Exception("服务器连接失败,请重新检查MySql服务是否打开。" + e.Message.ToString());
        }
    }

    public void CloseSql()	// 直接复制粘贴使用即可
    {
    
    
        if (con != null)
        {
    
    
            con.Close();
            con.Dispose();
            con = null;
        }
    }

    public void RawQuery(int stage, int val)	// 为一个具体的插入例子
    {
    
    
        DateTime dateTime = DateTime.Now;
        string sqlstr = string.Format("INSERT INTO {0} VALUES('{1}',{2},'{3}','{4}','{5}',{6},'{7}') "
        , tableName, id, stage, user_name, college_name, tel, val, dateTime);
        QuerySet(sqlstr);
    }

    private DataSet QuerySet(string sqlString)	// 直接复制粘贴使用即可
    {
    
    
        if (con.State == ConnectionState.Open)
        {
    
    
            DataSet ds = new DataSet();
            try
            {
    
    
                MySqlDataAdapter mySqlAdapter = new MySqlDataAdapter(sqlString, con);
                mySqlAdapter.Fill(ds);
            }
            catch (Exception e)
            {
    
    
                throw new Exception("SQL:" + sqlString + "/n" + e.Message.ToString());
            }
            finally
            {
    
    
            }
            return ds;
        }
        return null;
    }

结论

  • 本地调用成功,数据库内数据成功插入
    WebGL 项目中,数据库内数据插入失败
    原因:unity在webgl的平台下无法支持直连MySql
    在这里插入图片描述

方案二:创建中间php服务,通过UnityWebRequest调用,来执行mysql命令

  • 哈哈,好绕,但是是 chatGPT 在我最无助的时候提供的一个看似可行的方案。
    但我之前也没学过这俩玩意儿啊
    没事,一步一步来

php 编写

  • 通过 chatGPT 的引导,拥有了这么一份 index.php 文件
<?php

$servername = "your IP";
$username = "your user name";
$password = "your password";
$dbname = "your db name";

// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);

// 检查连接是否成功
if ($conn->connect_error) {
    
    
    die("连接失败: " . $conn->connect_error);
}

// 从HTTP请求中读取JSON数据
$json_data = file_get_contents('php://input');

// 将JSON数据解码为PHP数组
$data = json_decode($json_data, true);

// 插入数据到数据库表格
$sql = "INSERT INTO aniT VALUES ('".$data['id']."', '".$data['stage']."','".$data['college']."','".$data['tel']."','".$data['value']."','".$data['time']."')";
if ($conn->query($sql) === TRUE) {
    
    
    echo "插入成功";
} else {
    
    
    echo "Error: " . $sql . "<br>" . $conn->error;
}

// 关闭连接
$conn->close();
?>
  • 上述代码通过 httpRequest 传入json数据,然后转成 $data php数组,然后组合成 $sql mysql语句(一个字符串),最后执行。
    在这里插入图片描述
  • 第一次测试,可能对于大量代码测试比较麻烦,建议第一次使用下述代码进行测试
<?php
phpinfo();
?>

php 部署

  • 部署真是头疼。
    首先确保你的 Linux 宝塔下载了该 PHP,这个 5.X 的版本其实也能用。
    在这里插入图片描述
  • 打开配置文件,我们目前只需要关注 FPM配置文件
    查看 listen = XXXX注意这里监听的不是端口而是一个 sock复制该sock
    在这里插入图片描述
  • 打开 Nginx 配置文件,选择配置修改,往下翻到 server 这一块
    前面我们了解了 location 对于 html 的基本配置,也让我们成功打开了 WebGL 项目
    这里我们需要部署 php 文件,又大相径庭了…
    在这里插入图片描述
  • 之前没有配置过的话,需要新加入这一段
    fastcgi_pass 后面填写 unix: 再加刚刚的监听sock
    其他的照抄
    ,不然我就是打不开…
        location ~ \.php$ {
    
    
          fastcgi_pass   unix:/tmp/php-cgi-56.sock;
          fastcgi_index index.php;
          fastcgi_param SCRIPT_FILENAME     $document_root$fastcgi_script_name;
          include        fastcgi_params;
        }
  • 然后我把 index.php 传到了 root 目录,即 /www/wwwroot 目录下。
    通过 ip/index.php 可以尝试访问是否成功。
    我遇到了如下的问题。
    情况1:502 BadGate 估计是端口号没有放行,没有权限访问。
    情况2:404 :超链接 direct 失败,一般是你文件放错目录,或目录配置错误,或二级目录输入错了
    情况3:file not found 文件放错目录,或目录配置错误
    情况4:403 forbidden 貌似是权限问题
    在这里插入图片描述

(注:该php部署后打开就是类似一个网页,虽然它被叫做WebAPI,提供了其他的服务)
(但它貌似不是一个完整的WebAPI项目)

  • 一般多次尝试,对配置文件了解一下,就可以访问成功了。

C# 代码编写

  • 到这里我们再返回 Unity,在脚本中编写一些代码
    我们需要使用 UnityWebRequest 来访问上述的 php 服务。
    首先需要导入新的头文件 using UnityEngine.Networking;
    代码部分如下:
    public void RawQuery(int stage, int val)	// 一个测试函数
    {
    
    
        StartCoroutine(Insert(url, id, stage, college_name, tel, val, DateTime.Now));
    }
    // 具体的插入myqsl命令的函数
    IEnumerator Insert(string url, string id, int stage, string college, string tel, int value, DateTime time)
    {
    
    
        // 创建JSON数据
        string json = "{\"id\":\"" + id + "\",\"stage\":" + stage + ",\"college\":\"" + college + "\",\"tel\":\"" + tel + "\",\"value\":" + value + ",\"time\":\"" + time.ToString("yyyy-MM-dd HH:mm:ss") + "\"}";
        // Debug.Log(json);
        UnityWebRequest request = UnityWebRequest.Post(url, json);

        // 创建HTTP请求
        byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
        request.uploadHandler = new UploadHandlerRaw(bodyRaw);
        request.downloadHandler = new DownloadHandlerBuffer();
        request.SetRequestHeader("Content-Type", "application/json");
        // 发送HTTP请求
        yield return request.SendWebRequest();
        if (request.result == UnityWebRequest.Result.Success)
        {
    
    
            Debug.Log("Request successful!");
        }
        else
        {
    
    
            Debug.Log("Request failed!");
        }
        request.Dispose();

    }
  • 那么问题又来了
    疑惑一:WebGL 不是不支持 IEnumerator 吗?这里为什么可以用?
    在这里插入图片描述
    (你小子,肝反复横跳是吧!)
    好吧,经过我的思考,我得出了如下结论:
    虽然 WebGL 不支持 IEnumerator (大众风评,以及chatGPT的回复)
    虽然 WebGL 支持 UnityWebRequest (这点在unity官方文档中也有提出)
    但是 UnityWebRequest 支持 IEnumerator (WTF?)
    好吧,代码和我有一个能跑就行。
  • 疑惑二:那个 string json 的怪异格式
    就是单纯变成了一个字符串存储的json,unity把该字符串json传到php中再后续的解析。
    注意:对于varchar格式的数据,需要给引号,这也是常识。格式不对,后面你会遇到爆炸的问题(这里按下不表)。

A Native Collection has not been disposed, resulting in a memory leak.

  • 疑惑三: request.Dispose(); 一开始 chatGPT 没有让我写这句。
    不加的话,你就会在运行阶段遇到(一直遇到)可爱的:
    A Native Collection has not been disposed, resulting in a memory leak. ……
  • 后面没有更多报错信息,需要 packManager 导入一个新的包com.entity 啥的,但是导入后确实可以看到了,发现就是 UnityWebRequest.Post(url, json) 进去后报错了。
    但是之后运行阶段又出了
    RuntimeError: memory access out of bounds - gatsby development extremely slow
    在这里插入图片描述
    查看解决措施,貌似就是删掉没有用的 dll 等文件,就可以解决。所以我又把这个包给删了…
  • 额,那么 A Native Collection has not been disposed, resulting in a memory leak. ……
    的产生原因是什么呢?
    有人提出,各种各样的问题都会导致这个bug
    情况一:UnityWebRequest 使用后没有 Dispose
    情况二:mysql 语句语法错误(也就是我遇到的…)
  • 或者有博客推荐如下格式:
using(UnityWebRequest request = XXX){
    
    
	XXXX;
}

他们说这样退出的时候会自动使用 Dispose 方法,可能也行

其他我还遇到的一些问题

  • 我发现 Unity 导出的 WebGL ,其中 InputField ,移动端点击后居然没有输入的键盘…
    离谱,说好的 WebGL 支持各种设备呢,结果只是名义上支持…
    有说用虚拟键盘的,就是自己敲个代码之类的,居然还有人设置需要花 100R 来下载…
    我这里没办法,只能取消汉字输入,手写了一个点触数字输入的虚拟键盘了,寄。
  • WebGL 不支持移动端的横屏切换,输入键盘,基本的 IEnumerator,一些浏览器打不开,一些浏览器对音频播放不支持……唯一的优势也就是打开连接就能下载游玩吧。
  • 我这里只需要 insert 命令。如果需要 select 命令,就是需要 POST + GET 的,应该是差不多原理的,具体的也可以问问百度和 ChatGPT,使用C#中的 dataSet 类型存储GET来的数据。

猜你喜欢

转载自blog.csdn.net/weixin_45775438/article/details/130116593