Unity连接MySQL数据库(基础)
本文最后更新于2 天前,其中的信息可能已经过时,如有错误请发送邮件到1077511618@qq.com

Unity连接MySql数据库(基础)

为什么写这篇文章

网上其实已经有了不少unity连接MySql数据库(或其他数据库)的教程视频、文章,但是我找到的都是比较老的,使用较新版本(这里指8.0往后)的MySql connector的教程偏少,于是打算写此文,顺便记录个人学习经历、锻炼相关写作能力。
这是本人第一次写教程,在unity和数据库的方面还处于探索阶段(写此文的前一天晚上才通过ai和其他资料第一次实现了unity和mysql的连接(悲)),如有诸多不严谨之处,还望谅解,并非常欢迎在评论区留下您的建议、指正!

准备工作

我们需要Unity、MySql、MySql Connector三者,且要注意三者版本
个人使用工具版本:
Unity:2022.3.62f3c1;
MySql:8.0.45;
MySql Connector:8.0.28。
MySql Connector下载链接
注意:MySql Connector 最好同自身MySql版本相近,不然在unity中操作时可能会出现不兼容报错。

在有了上述工具后:

  1. 我们新建一个Unity工程,名为MySql_TestProject;
  2. 在项目的project窗口中,新建一个名为 Plugins 的文件夹,以放置我们需要的文件;
  3. 在Unity安装目录下找到I18N.dll、I18N.West.dll、System.Data.dll、System.Drawing.dll、I18N.CJK.dll、I18N.MidEast.dll文件复制拖入到Plugins文件夹中;
  4. 在刚刚下载好的MySql Connector安装目录下,选中v4.5.2 或 v4.8文件夹,拖入除MySql.Web.dll外的所有dll文件(老版本只用MySql.Data.dll就行,但是新版本需要其他依赖文件,可能不需要拖入那么多dll,我这里算是偷懒了)
    注意:如果添加了MySql.Web.dll,unity中会提示报错(示例):Assembly ‘Assets/Plugins/MySQL/mysql_connector/MySql.Web.dll’ will not be loaded due to errors:
    Unable to resolve reference ‘WebMatrix.WebData’. Is the assembly missing or incompatible with the current platform?
    Reference validation can be disabled in the Plugin Inspector
  5. 然后就是开始代码了~

示例项目效果

本教程中,我们希望我们的示例项目可以实现登录、注册功能,界面如下:

示例界面

示例数据库表

以下是我创建的一个数据库,存储了用户的信息:

示例用数据库

简单的MySql连接测试

为了验证我们的unity能正确同MySql数据库进行连接,我们添加以下脚本:

using System.Collections.Generic;
using UnityEngine;
using MySql.Data.MySqlClient;  // 注意一定要引用此命名空间才可使用mysql的API

public class DatabaseManager : MonoBehaviour
{
    [Header("MySql Connection")]
    public string server;
    public uint port;
    public string userID;
    public string password;
    public string database;
    public string database_table;
    [Header("MySql 查询示例命令")]
    public string MySQL_cmd;

    private MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder();
    // MySqlConnectionStringBuilder 是 MySQL Connector/NET 提供的一个连接字符串构建器类,用于类型安全地构建数据库连接字符串。(也可以不适用构建器直接连接字符串,但是不推荐)

    void Awake()
    {
        #region 配置连接串
        // 使用 MySqlConnectionStringBuilder 构建连接串
        builder.Server = server; // 指定 MySQL 服务器的 IP 地址或主机名
        builder.Port = port; // 指定 MySQL 服务器监听的端口号
        builder.UserID = userID; // 指定连接 MySQL 的用户名
        builder.Password = password; // 指定连接 MySQL 的密码
        builder.Database = database; // 指定连接后默认使用的数据库名称
        builder.CharacterSet = "utf8"; // 指定客户端与服务器通信时使用的字符集

        sqlConnection = new MySqlConnection(builder.ToString()); // 创建 MySQL 连接对象
        #endregion

        #region 简单的mysql连接及查询示例
        using (MySqlConnection connection = new MySqlConnection(builder.ToString()))
        {
            try
            {
                connection.Open(); // 建立与MySQL服务器的实际网络连接,首次打开可能较慢(握手、认证、加密协商)
                Debug.Log("连接 MySQL 成功!");

                // 简单查询示例
                MySqlCommand command = new MySqlCommand(MySql_cmd + " " + database_table + ";" , connection); // 在给定连接上执行SQL命令
                MySqlDataReader dataReader = command.ExecuteReader(); // 执行查询并返回结果,返回一个只读、只进的数据读取器
                while (dataReader.Read()) // 逐行读取数据
                {
                    Debug.Log(dataReader.GetString(0)); // 输出第一列数据信息
                }
                dataReader.Close(); // 关闭读取器
            }

            catch(MySqlException ex) // 如果连接失败,会抛出MySqlException
            {
                Debug.LogError("连接失败" + ex.Message);
            }

            finally
            {
                if (connection.State == System.Data.ConnectionState.Open)
                {
                    connection.Close();
                }
            }
        }
        #endregion
    }
}

将此脚本挂载到我们场景上新建的一个空物体(这里我命名为DatabaseManager)上,将各项参数输入后运行程序,就可以看到Unity控制台上打印出数据表第一列的信息。
注:请确保已经创建数据库并添加了表

输入各项参数:

参数输入

如果连接成功,可以看到输出了数据库我们要查询的表的第一列信息:

示例输出
;

到这里,恭喜你已经成功让unity和mysql数据库进行连接了!
注:UI界面的搭建这里不是要讲的重点,先跳过了~

实现登录和注册功能

这里我们要实现的登录功能的核心是实现对mysql数据库中的数据进行查询、比对,我们在DatabaseManager的脚本上直接进行修改。

核心是掌握mysql的相关api、数据库连接及读取流程、sql相关语法及数据库基础操作等,建议看示例代码中的相关注释哦!

直接看代码:
注册 & 从数据库读取用户信息:

using System.Collections.Generic;
using UnityEngine;
using MySql.Data.MySqlClient;

public class DatabaseManager : MonoBehaviour
{
    #region 单例实现
    private static DatabaseManager _instance;
    public static DatabaseManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<DatabaseManager>();
                if (_instance == null)
                {
                    GameObject go = new GameObject("DatabaseManager");
                    _instance = go.AddComponent<DatabaseManager>();
                    DontDestroyOnLoad(go);
                }
            }
            return _instance;
        }
    }
    #endregion

    [Header("MySql Connection")]
    public string server;
    public uint port;
    public string userID;
    public string password;
    public string database;
    public string database_table;
    [Header("MySql 查询示例命令")]
    public string MySql_cmd;

    [System.Serializable]
    public class User // 创建User类便于存储用户信息
    {
        public string Username;
        public string Useraccount;
        public string Userpassword;

        public User(string new_UserName = " ", string new_UserAccount = " " , string new_UserPassword = " ")
        {
            Username = new_UserName;
            Useraccount = new_UserAccount;
            Userpassword = new_UserPassword;
        }
    }

    public List<User> UserInfos = new List<User>(); // 创建用户信息列表

    #region sql类
    private MySqlConnection sqlConnection;
    private MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder();
    #endregion

    void Awake()
    {
        #region 配置连接串
        // 使用 MySqlConnectionStringBuilder 构建连接串
        builder.Server = server;
        builder.Port = port;
        builder.UserID = userID;
        builder.Password = password;
        builder.Database = database;
        builder.CharacterSet = "utf8";
        #endregion
        sqlConnection = new MySqlConnection(builder.ToString());

        #region 简单的mysql连接及查询示例
        using (MySqlConnection connection = new MySqlConnection(builder.ToString()))
        {
            try
            {
                connection.Open();
                Debug.Log("连接 MySQL 成功!");

                // 简单查询示例
                MySqlCommand command = new MySqlCommand(MySql_cmd + " " + database_table + ";" , connection);
                MySqlDataReader dataReader = command.ExecuteReader();
                while (dataReader.Read())
                {
                    Debug.Log(dataReader.GetString(0)); // 输出第一列数据
                }
                dataReader.Close();
            }

            catch(MySqlException ex)
            {
                Debug.LogError("连接失败" + ex.Message);
            }

            finally
            {
                if (connection.State == System.Data.ConnectionState.Open)
                {
                    connection.Close();
                }
            }
        }
        #endregion

        GetUserInfo();
    }

    #region 将从数据库读取到的信息添加到用户数据列表中
    void GetUserInfo()
    {
        string new_Name , new_Account , new_Password;

        sqlConnection.Open();
        MySqlCommand mysqlCommand = new MySqlCommand($"select * from {database_table}" , sqlConnection); // 查询命令
        MySqlDataReader mySqlDataReader = mysqlCommand.ExecuteReader(); // 执行查询命令并返回一个阅读器
        while (mySqlDataReader.Read()) // 逐行读取
        {
            new_Name = mySqlDataReader.GetString(0);
            new_Account = mySqlDataReader.GetString(1);
            new_Password = mySqlDataReader.GetString(2);

            User newUser = new User(new_Name , new_Account , new_Password);

            UserInfos.Add(newUser);
        }
        sqlConnection.Close();
    }
    #endregion

    #region 增添新的用户数据
    public void InsertNewUserInfo(User newUser)
    {
        sqlConnection.Open();
        MySqlCommand check_command = new MySqlCommand("select * from "+database_table , sqlConnection); // 查询表
        MySqlDataReader mySqlDataReader = check_command.ExecuteReader(); // 执行查询命令并返回结果集、包装成MySqlDataReader对象

        string col0 = mySqlDataReader.GetName(0); // 获取第一个字段名 / 列名
        string col1 = mySqlDataReader.GetName(1); // 获取第二个字段名
        string col2 = mySqlDataReader.GetName(2); // 获取第三个字段名

        mySqlDataReader.Close(); // 关闭阅读器(注意!!!执行下一个命令前要关闭先前打开的阅读器)

        MySqlCommand insert_command = new MySqlCommand($"insert into {database_table} ({col0},{col1},{col2}) values ('{newUser.Username}','{newUser.Useraccount}','{newUser.Userpassword}');" , sqlConnection); // 添加新用户信息(注册)
        insert_command.ExecuteNonQuery(); // 执行非查询命令

        UserInfos.Add(newUser);
        sqlConnection.Close(); // 关闭连接
    }
    #endregion
}
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class RegisterPanel : MonoBehaviour
{
    [Header("输入栏控件")]
    public TMP_InputField name_InputField;
    public TMP_InputField account_InputField;
    public TMP_InputField password_InputField;
    [Header("提示文本")]
    public TMP_Text remind_Text;

    #region 注册按钮监听事件
    public void onRegisterButtonClick()
    {
        // 检测用户名是否存在
        string input_name = name_InputField.text;
        foreach (DatabaseManager.User user in DatabaseManager.Instance.UserInfos)
        {
            if (input_name == user.Username)
            {
                remind_Text.text = "Registration failed! Username already exists!";
                return;
            }
        }

        // 检测账号是否重复
        string input_account = account_InputField.text;
        foreach (DatabaseManager.User user in DatabaseManager.Instance.UserInfos)
        {
            if (input_account == user.Useraccount)
            {
                remind_Text.text = "Registration failed! Account already exists!";
                return;
            }
        }

        // 当用户输入通过后,添加新用户数据
        string input_password = password_InputField.text;
        DatabaseManager.User newUser = new DatabaseManager.User(input_name , input_account , input_password);
        // 将新用户数据写入MySQL数据库中
        DatabaseManager.Instance.InsertNewUserInfo(newUser);

        remind_Text.text = "Registration successful!";
        Invoke("ClosePanel" , 0.5f);
        return;
    }

    void ClosePanel()
    {
        this.gameObject.SetActive(false);
    }
    #endregion
}

登录功能:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Org.BouncyCastle.Asn1.X509;
public class LoginPanel : MonoBehaviour
{
    [Header("输入框控件")]
    public TMP_InputField account_InputField;
    public TMP_InputField password_InputField;
    [Header("提示文本")]
    public TMP_Text remind_Text;

    #region 按钮监听事件
    public void onSignInButtonClick()
    {
        string input_account = account_InputField.text;
        string input_password = password_InputField.text;

        // 查询账号是否存在
        bool isAccountExited = false;
        DatabaseManager.User targetUser = new DatabaseManager.User();
        foreach (DatabaseManager.User user in DatabaseManager.Instance.UserInfos)
        {
            if (user.Useraccount == input_account)
            {
                targetUser = user;
                isAccountExited = true;
            }
        }
        if (!isAccountExited)
        {
            remind_Text.text = "Account does not exist!";
            return;
        }

        // 查询密码是否正确
        if (input_password != targetUser.Userpassword)
        {
            remind_Text.text = "Incorrect password!";
            return;
        }
        else
        {
            remind_Text.text = targetUser.Username + ", welcome!";
            return;
        }
    }
    #endregion
}

进行测试

我们运行程序,可以看到成功读取并储存了数据库表中的用户信息:

成功读取数据

随后进行登录测试,可以看到登录功能如期实现:

实现登录功能

最后进行注册测试,添加一个用户信息:

添加用户信息

(这里UI界面没调好……)

然后打开数据库命令窗口,查询一下是否添加了新的用户:

查询用户添加

可以看到,我们成功添加了一个用户!

在过程中你可能遇到的报错及解决建议

序号 报错信息 原因 解决方法
1 MySqlException: Authentication method 'caching_sha2_password' not supported MySQL 8.0+ 默认认证插件是 caching_sha2_password,旧版驱动不支持 ① 连接字符串加 SslMode=None;
② 或修改用户认证方式为 mysql_native_password
2 MySqlException: Client does not support authentication protocol requested by server 同上,驱动版本过旧 升级 Connector/NET 到 8.0+,或改用户认证插件
3 Assembly 'MySql.Web.dll' will not be loaded due to errors: Unable to resolve reference 'WebMatrix.WebData' MySql.Web.dll 是 ASP.NET 专用组件,依赖 System.Web,Unity 不支持 删除 MySql.Web.dll,只保留 MySql.Data.dll 及其核心依赖
4 Unable to resolve reference 'Google.Protobuf'. Is the assembly missing or incompatible with the current platform? Connector/NET 8.0+ 依赖 Google.Protobuf.dll 等库,未复制到 Plugins 从 Connector/NET 安装目录复制所有依赖 dll 到 Plugins
5 KeyNotFoundException: The given key 'utf8mb4' was not present in the dictionary. Connector/NET 6.x 字符集映射表不包含 utf8mb4 连接字符串加 CharSet=utf8; 或升级到 Connector/NET 8.0+
6 KeyNotFoundException: The given key 'utf8mb3' was not present in the dictionary. 同上,6.x 驱动不认识 utf8mb3 连接字符串加 CharSet=utf8;CharSet=latin1;,或升级驱动
7 MySqlException: You have an error in your SQL syntax... near ''user_name','user_account','user_password') 列名被单引号包裹,MySQL 将其当作字符串而非列名 去掉列名两端的单引号,或改用反引号 `
8 ArgumentException: Keyword not supported. Parameter name: sslmode 旧版 Connector/NET 不支持 SslMode 参数 去掉 SslMode=None;,改用修改 MySQL 认证插件的方式
9 Assembly 'MySql.Data.dll' will not be loaded due to errors: Reference has errors dll 版本不兼容或缺少依赖项 检查是否用了正确的 dll 版本(v4.5.2/v4.8),补齐所有依赖
10 'UserInfo' is missing the class attribute 'ExtensionOfNativeClass' Unity 尝试序列化普通 C# 类,类名可能与 Unity 内部类冲突 ① 加 [System.Serializable]
② 改为 private class 内部类
③ 改类名
④ 删除 Library 文件夹清理缓存
11 MySqlException: There is already an open DataReader associated with this Connection 一个连接同时只能有一个打开的 DataReader 执行下一个命令前先 mySqlDataReader.Close()
12 Unity 一直在 Reloading Domain Domain Reload 卡住,常见于静态变量或 DLL 加载问题 ① 删除 LibraryTemp 文件夹
② 或取消勾选 Reload Domain(Edit → Project Settings → Editor → Enter Play Mode Settings)
13 MySqlException: Unable to connect to any of the specified MySQL hosts 网络问题或 MySQL 服务未启动 ① 检查 MySQL 服务是否运行
② 检查 IP/端口是否正确
③ 尝试用 127.0.0.1 替代 localhost
14 MySqlException: Access denied for user 'root'@'localhost' 用户名或密码错误 确认用户名密码正确,或重置 MySQL 密码
15 NullReferenceException: Object reference not set to an instance of an object sqlConnection 未初始化,或 DataReader 读取空值 检查 builder.ToString() 是否成功,检查数据库是否有数据

最后

因本人也是在处于探索阶段,示例的代码、知识点的讲述难免有许多问题(如我是直接直接拼接用户输入来给数据库插入信息,而非参数化查询,这可能会导致数据混乱或泄露),后续通过进一步的学习探索,会进行相关更新。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇