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

Unity 2017.2+C#数据库类动态切换实现方案咨询

实现思路与代码示例

嘿,这个需求其实是策略模式+单例/依赖注入的经典应用场景,刚好能完美解决你这种多数据库动态切换的需求,我给你一步步拆解具体实现:

1. 确保抽象类是统一契约

首先要保证你的DatabaseTemplate抽象类定义了所有需要对外暴露的方法,作为两个派生类的统一接口:

public abstract class DatabaseTemplate
{
    // 定义你需要的所有抽象方法,比如QueryScalar、ExecuteNonQuery等
    public abstract object QueryScalar(string sql);
    public abstract int ExecuteNonQuery(string sql);
    // 其他数据库操作方法...
}

2. 完善派生类的实现

你的BaseMysql和BaseSQlite只需要正确继承抽象类,并实现所有抽象方法即可(注意处理各自的数据库连接和类库依赖):

// MySQL实现类
public class BaseMysql : DatabaseTemplate
{
    private MySqlConnection _dbConnection;

    // 构造函数初始化连接
    public BaseMysql(string connectionString)
    {
        _dbConnection = new MySqlConnection(connectionString);
        _dbConnection.Open();
    }

    public override object QueryScalar(string sql)
    {
        using (var cmd = new MySqlCommand(sql, _dbConnection))
        {
            return cmd.ExecuteScalar();
        }
    }

    public override int ExecuteNonQuery(string sql)
    {
        using (var cmd = new MySqlCommand(sql, _dbConnection))
        {
            return cmd.ExecuteNonQuery();
        }
    }
    // 其他方法实现...
}

// SQLite实现类
public class BaseSQlite : DatabaseTemplate
{
    private SQLiteConnection _dbConnection;

    public BaseSQlite(string connectionString)
    {
        _dbConnection = new SQLiteConnection(connectionString);
        _dbConnection.Open();
    }

    public override object QueryScalar(string sql)
    {
        using (var cmd = _dbConnection.CreateCommand())
        {
            cmd.CommandText = sql;
            return cmd.ExecuteScalar();
        }
    }

    public override int ExecuteNonQuery(string sql)
    {
        using (var cmd = _dbConnection.CreateCommand())
        {
            cmd.CommandText = sql;
            return cmd.ExecuteNonQuery();
        }
    }
    // 其他方法实现...
}

3. 实现统一的DatabaseManager

这个类是核心,负责初始化具体数据库实例,并对外暴露统一的调用入口。考虑到Unity的场景,用单例模式最合适:

public class DatabaseManager : MonoBehaviour
{
    private DatabaseTemplate _currentDbInstance;
    // 全局单例实例,确保整个游戏只有一个数据库管理器
    public static DatabaseManager Instance { get; private set; }

    private void Awake()
    {
        // 单例逻辑,避免重复创建
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);

        // 这里可以从配置文件、PlayerPrefs或Inspector读取数据库类型
        // 示例:默认用SQLite,可通过PlayerPrefs切换到MySQL
        string dbType = PlayerPrefs.GetString("ActiveDatabase", "SQLite");
        string connectionStr = GetConnectionString(dbType);
        
        // 初始化对应数据库实例
        InitializeDatabase(dbType, connectionStr);
    }

    // 根据数据库类型返回对应的连接字符串
    private string GetConnectionString(string dbType)
    {
        return dbType switch
        {
            "MySQL" => "server=localhost;user=root;password=your_pwd;database=your_db",
            "SQLite" => "URI=file:game_db.db",
            _ => throw new ArgumentException($"不支持的数据库类型:{dbType}")
        };
    }

    // 初始化具体数据库实例
    private void InitializeDatabase(string dbType, string connectionStr)
    {
        _currentDbInstance = dbType switch
        {
            "MySQL" => new BaseMysql(connectionStr),
            "SQLite" => new BaseSQlite(connectionStr),
            _ => throw new ArgumentException($"无法初始化数据库:{dbType}")
        };
    }

    // 对外暴露的统一方法,直接转发给当前数据库实例
    public object QueryScalar(string sql)
    {
        ValidateDbInstance();
        return _currentDbInstance.QueryScalar(sql);
    }

    public int ExecuteNonQuery(string sql)
    {
        ValidateDbInstance();
        return _currentDbInstance.ExecuteNonQuery(sql);
    }

    // 辅助方法:检查数据库实例是否已初始化
    private void ValidateDbInstance()
    {
        if (_currentDbInstance == null)
        {
            throw new InvalidOperationException("数据库实例未初始化,请检查配置");
        }
    }
}

4. 使用方式

在Unity中,把DatabaseManager脚本挂在一个空物体上(比如命名为"DatabaseManager"),然后在任何需要调用数据库的地方直接使用:

// 示例:获取用户总数
void GetTotalUsers()
{
    try
    {
        object userCount = DatabaseManager.Instance.QueryScalar("SELECT count(*) FROM users");
        Debug.Log($"当前用户总数:{userCount}");
    }
    catch (Exception ex)
    {
        Debug.LogError($"查询用户总数失败:{ex.Message}");
    }
}

额外优化建议

  • 把数据库配置(类型、连接字符串)做成ScriptableObject,这样可以直接在Unity Inspector里修改,不用改代码;
  • 增加连接池管理和异常统一处理,提升稳定性;
  • 如果后续需要支持更多数据库,只需要新增一个继承DatabaseTemplate的派生类,再在DatabaseManager的初始化逻辑里加一个case即可,完全符合开闭原则。

内容的提问来源于stack exchange,提问作者Maikel Urlitzki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:57:49