十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Unity 2018连接MySQL实战:驱动配置、C#实现与跨平台方案

Unity 2018连接MySQL实战:驱动配置、C#实现与跨平台方案 在开发中第一次想用Unity 2018连接MySQL数据库时我本以为写个连接字符串、调个驱动就能跑通结果在环境配置上反复碰壁。后来才意识到Unity本身是游戏引擎不是Web后端它默认的脚本运行时、API兼容级别、依赖管理方式都跟常规的.NET项目不一样驱动版本、MySQL认证方式、连接权限这几个环节一旦不匹配哪怕代码写得再对也只能干瞪眼。这篇文章就把Unity 2018直连MySQL的完整链路梳理清楚从MySQL安装、Connector驱动选型、Unity工程配置到第一段C#代码、常见报错排查、数据操作进阶再到Android和WebGL平台上的替代方案做数据库课程设计或者小型游戏项目的朋友可以直接照着操作。1. 为什么Unity 2018直连MySQL会这么折腾先看清完整链路1.1 数据是怎么从游戏场景跑到数据库的很多人第一次在Unity里接数据库会误以为像组件拖拽那样拖个脚本就能连上实际上完全不是。Unity中的C#脚本是通过MySql.Data这个驱动用TCP连接远程或本地的MySQL服务器然后发送SQL命令再接收查询结果。整条链路大致是场景对象 - MonoBehaviour脚本 - MySql.Data驱动 - TCP Socket - MySQL服务器 - InnoDB存储引擎这条链路里的任何一个环节出错都会表现为连不上但原因可能完全不同。比如驱动类型不对、数据库服务没启动、用户没有远程权限、防火墙拦了3306端口、连接字符串里的库名写错、甚至MySQL 8.0的默认认证方式跟旧版驱动不兼容这些都能让连接报错。第一次踩坑时最容易忽略的是Unity 2018本身的脚本运行时版本。如果没提前配置好后面所有报错都像是在绕迷宫。1.2 Unity 2018的脚本运行时和API兼容级别是怎么回事Unity 2018默认情况下脚本运行时使用的是.NET 3.5API兼容级别一般也是.NET 3.5。而MySQL官方驱动Connector/Net 8.0是基于.NET 4.5.2编译的。也就是说如果你什么都不改直接往Unity 2018工程里丢一个MySql.Data.dll运行时大概率会报MissingMethodException或FileNotFoundException编译器也可能直接不认命名空间。原因很简单.NET 3.5这个运行时太老了很多驱动依赖的新API根本不存在。解决办法是在Unity 2018里把脚本运行时切换到.NET 4.x Equivalent同时把API兼容级别也改成.NET 4.x。具体路径是Edit - Project Settings - Player - Other Settings - Configuration然后在配置项里找到Scripting Runtime Version -.NET 4.x EquivalentApi Compatibility Level -.NET 4.x需要注意的是Unity 2018中这个选项在不同小版本里叫法略有差异。2018.1到2018.2里可能写成.NET 4.6 Equivalent2018.3之后统一叫.NET 4.x Equivalent但本质都是同一套东西。改了之后Unity会重新编译脚本可能耗时几十秒有时还会提示编辑器需要重启。这一步属于常规操作不是异常。2. 环境准备MySQL安装、Connector版本选择与Unity工程配置2.1 MySQL 5.7与8.0到底选哪个大多数人在自己机器上装MySQL往往是从官网随便下载一个版本然后一路Next。实际上版本选择直接决定了后面驱动怎么配。如果你用的是Unity 2018建议优先选择MySQL 5.7或者安装MySQL 8.0时注意认证方式。原因是MySQL 8.0默认把认证插件改成了caching_sha2_password而较老的Connector/Net 6.9系列根本不认这种认证方式连接时会直接报Authentication method caching_sha2_password not supported by any of the available plugins就算你用Connector/Net 8.0也建议在连接字符串里加上SslModeNone和AllowPublicKeyRetrievaltrue否则连接时容易因为SSL协商失败而报错。我的个人习惯是在开发机上用MySQL 5.7.42跟Unity 2018搭配最省心。如果必须用MySQL 8.0安装过程中有一个步骤会询问认证方式记得选择Use Legacy Authentication或者安装后执行下面这句把root切回旧认证ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;这样做不是因为MySQL 8.0的新认证不安全纯粹是为了兼容老驱动。2.2 Connector/Net驱动要选哪个版本下载后放到哪里驱动版本的选择遵循一个原则别追新要追兼容。Unity 2018配合.NET 4.x使用时推荐下载MySQL Connector/Net 8.0.11。这个版本发布于2018年跟Unity 2018处在同一时代依赖很少编译目标也是.NET 4.5.2放进Unity里不会有奇奇怪怪的依赖问题。如果下载太新的Connector/Net 8.0.30或8.0.33你会发现MySql.Data.dll旁边多了一堆第三方依赖DLL比如Google.Protobuf.dll、K4os.Compression.LZ4.Streams.dll这些文件缺一个都会在运行时给你惊喜。另一个坑是安装Connector/Net时如果你电脑上同时装了Office或Visual Studio安装过程可能提示需要某种.NET框架版本。这时不需要装额外的运行时直接去MySQL官网的下载归档页面找到对应版本下载No thanks, just start my download开头的zip包就行解压后从Assemblies/v4.5.2目录里取MySql.Data.dll。然后把MySql.Data.dll复制到Unity工程的Assets/Plugins目录下。如果Plugins文件夹不存在就自己创建一个。提示不要放在Assets根目录下也不要放在Resources目录。放进Plugins是为了告诉Unity这是需要打包并参与编译的原生依赖库。如果之后在运行时报错说缺少MySql.Data.dll多半是文件没放在Plugins里或文件名被Unity改了。2.3 在Unity 2018工程里完成最后的配置DLL放好之后还需要做两步第一步打开Edit - Project Settings - Player - Other Settings - Configuration把Scripting Runtime Version和Api Compatibility Level都切换为.NET 4.x。第二步回到脚本里在文件头部引入命名空间using MySql.Data.MySqlClient;如果编译器报告找不到MySql.Data快捷键CtrlShiftR搜索一下工程里是否存在MySql.Data.dll。特别注意Unity有时候不会自动刷新外部DLL需要点击一下编辑器窗口让它重新导入或者用Assets - Refresh快捷键CtrlR。到这里环境才算真正准备好。3. 第一段连接代码从连接字符串到数据读取的完整示例3.1 连接字符串里的每一项到底是什么意思连接字符串是MySQL连接里最容易写错的部分。一个典型的连接字符串长这样string connStr Server127.0.0.1;Port3306;Databasegame_db;Uidroot;Pwd123456;Charsetutf8mb4;SslModeNone;;这里每个参数都有它的作用ServerMySQL服务器的IP地址。如果MySQL和Unity跑在同一台电脑上用127.0.0.1尽量不要用localhost因为某些系统上localhost会被解析成IPv6导致连接慢。PortMySQL默认3306如果你装MySQL时改过端口这里要跟着改。Database要连接的数据库名必须提前在MySQL里创建好。Uid和Pwd数据库用户名和密码。如果提示权限不足先检查这里。Charset强烈建议写成utf8mb4否则中文数据在读取时非常容易变成问号。SslMode开发阶段直接用None让连接走非SSL通道。生产环境才需要配置真正的SSL证书。这一段字符串看起来简单可它几乎概括了90%的连接失败原因。3.2 完整的读写脚本查询、插入、更新、删除下面写一个可以在Unity场景里直接挂到Camera上的测试脚本演示最基本的增删改查using UnityEngine; using MySql.Data.MySqlClient; public class DatabaseTest : MonoBehaviour { private string connStr Server127.0.0.1;Port3306;Databasegame_db;Uidroot;Pwd123456;Charsetutf8mb4;SslModeNone;; void Start() { QueryTopPlayers(); InsertPlayer(new_player, 88); QueryTopPlayers(); } void QueryTopPlayers() { using (MySqlConnection conn new MySqlConnection(connStr)) { conn.Open(); string sql SELECT id, username, score FROM player ORDER BY score DESC LIMIT 10; MySqlCommand cmd new MySqlCommand(sql, conn); using (MySqlDataReader reader cmd.ExecuteReader()) { while (reader.Read()) { Debug.Log($id{reader[id]}, name{reader[username]}, score{reader[score]}); } } } } void InsertPlayer(string username, int score) { using (MySqlConnection conn new MySqlConnection(connStr)) { conn.Open(); string sql INSERT INTO player (username, score) VALUES (name, score); MySqlCommand cmd new MySqlCommand(sql, conn); cmd.Parameters.AddWithValue(name, username); cmd.Parameters.AddWithValue(score, score); cmd.ExecuteNonQuery(); } } }这段代码里用到了两个using。第一个using负责构造函数第二个using负责释放数据库连接。在Unity里数据库连接用完之后必须释放否则每次查询都会占用MySQL的服务端连接一段时间后会出现Too many connections报错。MySqlCommand里的参数化查询也非常重要。有人喜欢直接拼接SQLstring sql SELECT * FROM player WHERE username username ;一旦用户名里包含单引号或者SQL关键字轻则查询出错重则直接被注入删库。参数化的习惯一定要从第一天养成。3.3 先建表再跑脚本的建议运行上面的脚本之前需要在MySQL里建好数据库和表。建议在Navicat或MySQL命令行里执行CREATE DATABASE IF NOT EXISTS game_db DEFAULT CHARSET utf8mb4; USE game_db; CREATE TABLE IF NOT EXISTS player ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, score INT DEFAULT 0 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里的字符集指定成utf8mb4可以同时兼容数字、字母、中文、emoji算是MySQL开发里的标配。如果你完全不知道MySQL怎么操作最简单的办法是先装好MySQL Workbench用图形界面建库建表连接测试成功后再把数据搬到Unity里读。4. 常见报错与排查链路从编译失败到连接超时真正上手时几乎每个人都会碰到几个报错。这里把我见过的高频问题按排查顺序整理一遍。4.1 编译期找不到MySql.Data或命名空间不存在这类问题最常见也最简单。确认DLL在Assets/Plugins目录下。确认Unity 2018已经切换到.NET 4.x。确认脚本里写的是using MySql.Data.MySqlClient;而不是using MySQL;大小写和点分结构都不能错。如果DLL是从网上下载的右键DLL文件查看文件大小太小的文件往往不是完整程序集。4.2 运行期Authentication method caching_sha2_password not supported这句话如果出现过就是因为Connector/Net版本和MySQL 8.0的默认认证方式不兼容。做法分两条路如果用的是MySQL 8.0把root用户重新设置成mysql_native_password认证。或者把MySQL降级到5.7。或者升级Connector/Net到8.0.11以上版本再在连接字符串里加上SslModeNone;AllowPublicKeyRetrievaltrue;。从稳定角度讲新项目遇到这个坑直接选择使用MySQL 5.7或者用旧认证迁移往往比升级驱动更快解决问题。4.3 运行期Host xxx is not allowed to connect to this MySQL server这个报错表示你的MySQL用户不允许从当前客户端IP登录。MySQL的新装环境里root用户默认只允许localhost本地登录而Unity脚本是通过局域网IP访问数据库服务器的。这时候就需要创建一个专门给Unity用的数据库账号CREATE USER unity_user% IDENTIFIED BY your_password; GRANT ALL PRIVILEGES ON game_db.* TO unity_user%; FLUSH PRIVILEGES;执行完之后连接字符串就要改成ServerMySQL服务器IP;Port3306;Databasegame_db;Uidunity_user;Pwdyour_password;Charsetutf8mb4;SslModeNone;注意%表示允许从任意IP连接局限性是任何人都能尝试登录好在有密码保护课程设计或内网演示完全够用。4.4 运行期连接超时或10061无法连接连接超时大概率是网络层问题按下面顺序检查先确认MySQL服务启动了没有。Windows下按WinR输入services.msc找到MySQL服务看状态是否为正在运行。确认端口。命令行输入telnet 127.0.0.1 3306能连上说明本机端口没问题。关掉Windows防火墙或添加入站规则放行3306端口。如果MySQL在虚拟机或云服务器上还需要在云安全组里放行。确认Unity所在机器和MySQL服务器在同一个局域网或网络可达。如果是Docker启动的MySQL那还要检查容器启动时有没有把3306端口映射到宿主机例如docker run --name mysql57 -p 3306:3306 -e MYSQL_ROOT_PASSWORD123456 -d mysql:5.7-p 3306:3306这一步漏掉外部就永远连不上容器里的MySQL。4.5 查询没报错但是中文全是??????中文乱码的原因通常是连接字符集和表字符集不一致。解决方案有三个地方要同时设置MySQL表用utf8mb4。连接字符串里写Charsetutf8mb4。SQL文件如果是导入生成的确保文件本身以UTF-8保存。如果做完这三步依然乱码再查看SET NAMES utf8mb4;是否在建立连接后自动生效。我的建议是直接通过ALTER TABLE把表和字段统一成utf8mb4。4.6 数据卡顿、编辑器无响应这是Unity直连数据库最典型的体验问题。如果恰好在Update()里写了个ExecuteReader()那么每一帧都要跟数据库进行一次同步通信数据库响应一慢Unity主线程直接被锁住表现就是画面卡成了PPT。这个问题的正确解法放到下一节详细讲。5. 数据操作进阶参数化查询、协程与连接复用5.1 为什么不能在Update里直接执行SQL数据库查询是IO操作本地查询通常几毫秒到几十毫秒但一旦涉及网络传输、数据量大、索引缺失一次查询可能几百毫秒。Unity的逻辑是在主线程里执行的而主线程又要负责渲染、输入、物理模拟任何一个同步阻塞都会造成卡顿。所以我的习惯是凡是数据库操作全部放到后台线程或协程里执行绝不放到Update或FixedUpdate里同步执行。5.2 用协程把查询放到后台执行Unity本身没有真正的多线程UI控制权协程可以配合ThreadPool或Task.Run来实现异步查询。下面是一个简单可靠的模式using System.Collections; using System.Threading.Tasks; using UnityEngine; using MySql.Data.MySqlClient; public class AsyncDatabaseTest : MonoBehaviour { private string connStr Server127.0.0.1;Port3306;Databasegame_db;Uidroot;Pwd123456;Charsetutf8mb4;SslModeNone;; void Start() { StartCoroutine(LoadDataRoutine()); } IEnumerator LoadDataRoutine() { Taskstring task Task.Run(() QueryPlayerCount()); while (!task.IsCompleted) { yield return null; } if (task.Exception ! null) { Debug.LogError(task.Exception.Message); } else { Debug.Log(task.Result); } } string QueryPlayerCount() { using (MySqlConnection conn new MySqlConnection(connStr)) { conn.Open(); MySqlCommand cmd new MySqlCommand(SELECT COUNT(*) FROM player, conn); return cmd.ExecuteScalar().ToString(); } } }这段代码的好处是Task.Run把耗时的查询放到线程池里执行。yield return null让Unity主线程每帧都有机会处理渲染查询完成前不会卡住界面。查询完成后自动回到主线程然后打印结果。Task.Run在Unity 2018的.NET 4.x下可以直接使用不用额外安装任何包。5.3 连接复用和批次操作的经验数据库连接本身是有成本的频繁new MySqlConnection、Open、Close高并发下性能会很差。但Unity端往往没有特别高的并发所以不要为了性能把连接做成全局单例一直开着因为移动App切到后台时连接很容易失效。我的折中做法是写一个DatabaseHelper把连接字符串统一管理。每次操作都using释放。如果确实有大量插入需求用批量SQL或事务处理不要一条条插入。批量插入的简单示例using (MySqlConnection conn new MySqlConnection(connStr)) { conn.Open(); using (MySqlTransaction trans conn.BeginTransaction()) { MySqlCommand cmd new MySqlCommand(); cmd.Connection conn; cmd.Transaction trans; for (int i 0; i 1000; i) { cmd.CommandText $INSERT INTO player (username, score) VALUES (player_{i}, {i}); cmd.ExecuteNonQuery(); } trans.Commit(); } }事务的意义在于要么全部成功要么全部失败而且同一个事务内部只会提交一次比单独执行1000条命令快很多。5.4 数据库备份和同步的入门提醒跟MySQL打交道还会遇到另一个频繁被搜索的问题数据库备份和同步。说实话Unity连MySQL这件事本身只是读和写但一旦你开始往库里写正式数据就一定要考虑备份。我的做法是建一个最简单的自动备份脚本用mysqldump把整个库导出成SQL文件再配合Windows计划任务每天执行echo off set timestamp%date:~0,4%%date:~5,2%%date:~8,2% mysqldump -uroot -p123456 game_db D:\backup\game_db_%timestamp%.sql如果你的项目需要多人共用一套数据库还可以研究一下MySQL Replication这类同步机制。不过这只是运维层面的补充核心思路还是连上只是开始数据安全和备份意识才是长期使用MySQL的关键。6. 跨平台发布Android、WebGL上还能直连MySQL吗6.1 Android / iOS / WebGL的连库差异在Windows或Mac编辑器里直连MySQL没有任何问题但一谈到打包发布情况就变了。Android技术上可以直连MySQLMySql.Data.dll属于托管程序集Android的Mono和IL2CPP都能加载。但实际坑很多比如Android设备需要联网权限、不同手机的DNS解析差异、驱动在某些CPU架构下的AOT限制。在Android上直连MySQL不是不行而是风险高、调试困难。iOSiOS对AOT编译要求极严MySql.Data.dll在IL2CPP下经常会因为JIT依赖或AOT裁剪报错。就算能编过测试也会花掉大量时间。WebGL基本不用考虑直连MySQL。WebGL运行在浏览器沙箱里直接走TCP Socket去连3306端口绝大多数浏览器都禁止。即使技术上绕过也会遇到跨域、TCP支持缺失等一连串问题。所以我的结论很明确如果你只是做Windows平台的课程设计直连MySQL完全够用。如果你准备发布到Android或WebGL趁早换方案。6.2 HTTP网关方案用PHP/Python/Node.js把MySQL包成API直连MySQL有平台限制为什么不换个思路呢在服务器上部署一个轻量HTTP接口由后端脚本负责跟MySQL交互Unity端用UnityWebRequest去请求这个接口拿JSON数据。这个方案有几个明显好处跨平台通用WebGL也能用。数据库连接串只存在服务器不会被打包进客户端。可以在网关层统一做缓存、权限控制、日志。对Unity端而言只需要处理HTTP请求和JSON解析不需要引入MySql.Data.dll。最简单的实现用一个Python Flask脚本就够from flask import Flask, jsonify import pymysql app Flask(__name__) app.route(/api/top) def top(): conn pymysql.connect(host127.0.0.1, userroot, password123456, databasegame_db, charsetutf8mb4) cur conn.cursor() cur.execute(SELECT username, score FROM player ORDER BY score DESC LIMIT 10) rows cur.fetchall() conn.close() return jsonify(rows) if __name__ __main__: app.run(host0.0.0.0, port5000)Unity端请求这个接口也很简单using UnityEngine; using UnityEngine.Networking; using System.Collections; public class ApiClient : MonoBehaviour { IEnumerator FetchTopPlayers() { using (UnityWebRequest request UnityWebRequest.Get(http://127.0.0.1:5000/api/top)) { yield return request.SendWebRequest(); if (request.result UnityWebRequest.Result.Success) { Debug.Log(request.downloadHandler.text); } } } }从维护角度看这个方案反而比直连数据库优雅得多。数据库驱动、连接串、SQL版本差异都被隔离在后端Unity端只需要面对一个稳定的HTTP接口。6.3 个人实操建议什么情况该直连什么情况别直连结合我自己的经验给出下面几条判断标准Windows/Mac单机演示、局域网课设、临时工具优先直连MySQL简单直接。Android真机调试且数据量不大直连勉强可行但要提前测试IL2CPP编译和国内ROM的TCP权限问题。任何准备上线给真实用户使用的产品都不要让客户端直连数据库。只要有WebGL发布需求直接走HTTP网关。在实际操作中我最常用的组合是Unity 2018 MySQL 5.7 Connector/Net 8.0.11 简单协程异步开发调试阶段直连等核心功能稳定后再花一天时间把查询接口换成HTTP网关。这样既能快速看到数据效果又不至于在平台适配阶段把自己困死。最后再分享一个小技巧如果你用Unity个人版做课程设计发布后启动时会显示Unity Logo但使用免费的专业版功能去关闭Logo并不现实演示时可以提前打开已编译好的客户端先进入场景再开始展示。重心还是放在数据库功能演示上别被启动画面占用了宝贵的验收时间。
返回列表