MySqlConnector 패키지를 이용하여 DB와 통신할 수 있습니다. static 메서드를 통해 별도의 인스턴스 없이 편리하게 접근하여 DB 쿼리를 작성할 수 있도록 구현합니다.
📺 미리 보기
💬 서론
- '미리보기'에 나오는 영상은 Morph! 게임에서 사용자의 로그인을 하는 과정입니다.
- 작성한 'MySqlManager' 클래스는 서버에 구현되어있으며, 클라이언트는 서버를 통해 DB에 접근하는 방식입니다.
- 이렇게 구현한 이유는 MySQL에 접근하기위한 접속쿼리가 클라이언트 코드에 노출되지 않게 하기 위함입니다.
- 클라이언트의 디컴파일을 통해 리터럴이 노출되면 DB 자체가 공격을 받을 수 있기 때문입니다.
📖 구현 내용
- MySqlManager에서는 Insert, Update 등을 수행할 수 있는 'Command' 메서드와 데이터를 읽기 위한 'Select' 메서드를 구현하였습니다.
⚒️ 구현
· 구현 내용
using MySqlConnector;
using Server.Game;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
/// MySQL 쿼리 매니저
/// </summary>
public class MySqlManager
{
private static ThreadLocal<MySqlConnection> _Connection = new ThreadLocal<MySqlConnection>(); // SQL Connection
private static string _SqlConnection = null; //SQL 접속 명령인자
static MySqlManager()
{
// 접속 명령인자 생성
StringBuilder builder = new StringBuilder();
builder.AppendFormat("Server={0};", "192.168.0.1"); // DB가 설치된 ID
builder.AppendFormat("Port={0};", "1234"); // DB의 포트 번호
builder.AppendFormat("Database={0};", "sampleDB"); // 데이터베이스 이름
builder.AppendFormat("Uid={0};", "sampleUser"); // 사용자 이름
builder.AppendFormat("Pwd={0}", "samplePassword"); // 사용자의 비밀번호
_SqlConnection = builder.ToString();
}
private static void MySqlConnect()
{
try
{
_Connection.Value = new MySqlConnection(_SqlConnection);
_Connection.Value.Open();
if (_Connection.Value.State != ConnectionState.Open)
{
throw new InvalidOperationException("Connection failed to open.");
}
}
catch (Exception ex)
{
Logger.Log(ex.Message);
}
}
private static void MySqlDisconnect()
{
if (_Connection.Value != null && _Connection.Value.State != ConnectionState.Closed)
{
_Connection.Value.Close();
_Connection.Value = null;
}
}
public static MySqlErrorCode Command(string command)
{
Logger.Log($"[SELECT]: {command}");
MySqlConnect(); // 접속
try
{
MySqlCommand dbcmd = new MySqlCommand(command, _Connection.Value); // 명령어를 커맨드에 입력
dbcmd.ExecuteNonQuery(); // 명령어를 SQL에 보냄
return MySqlErrorCode.None;
}
catch (MySqlException e) // SQL 오류
{
Logger.Log(e.ToString());
return e.ErrorCode;
}
finally
{
MySqlDisconnect(); // 접속 해제
}
}
public static DataTableReader Select(string command)
{
Logger.Log($"[SELECT]: {command}");
MySqlConnect(); // 접속
try
{
MySqlDataAdapter adapter = new MySqlDataAdapter(command, _Connection.Value);
DataTable table = new DataTable(); // 테이블 생성
adapter.Fill(table); // 데이터 테이블 채우기
return table.CreateDataReader(); // 성공적으로 select를 했다면, 데이터 리더를 생성
}
catch (MySqlException e) // SQL 오류 발생
{
Logger.Log(e.ToString());
return null;
}
finally
{
MySqlDisconnect(); // 접속 해제
}
}
}
builder.AppendFormat("Server={0};", "192.168.0.1"); // DB가 설치된 ID
builder.AppendFormat("Port={0};", "1234"); // DB의 포트 번호
builder.AppendFormat("Database={0};", "sampleDB"); // 데이터베이스 이름
builder.AppendFormat("Uid={0};", "sampleUser"); // 사용자 이름
builder.AppendFormat("Pwd={0}", "samplePassword"); // 사용자의 비밀번호
- 이곳에서 접속할 데이터베이스의 접속인자를 정의합니다. 이 코드에서는 임시로 채워넣었습니다.
public static MySqlErrorCode Command(string command)
- Command 메서드는 테이블을 읽지 않는 쿼리를 요청할때 사용할 수 있습니다.
- MySqlErrorCode를 리턴하여 성공적으로 Command를 수행했는지 확인할 수 있습니다.
public static DataTableReader Select(string command)
- Select 메서드는 테이블을 읽고, 이를 리턴하기위해 사용할 수 있습니다.
- 사용자의 로그인, 회원가입 읽기 등 다양한 부분에서 사용합니다.
✅ 적용
· Command
public static void AddCoin(int playerUniqueId, int amount)
{
DataTableReader balanceInfo = MySqlManager.Select($"select coins from balance where user_id = {playerUniqueId}");
if (balanceInfo.Read())
{
MySqlManager.Command($"update balance set coins = {balanceInfo.GetInt32(0) + amount} where user_id = {playerUniqueId};");
}
else
{
Logger.Log($"[ERROR EXCEPTION] No {playerUniqueId} Level Column from DB!");
}
}
- 다음과 같이 Command를 사용할 수 있습니다.
- Command는 UPDATE문 등 테이블을 읽지 않는 쿼리를 사용하기 위한 메서드입니다.
· Select
/// <summary>
/// 플레이어의 현재 인벤토리 정보를 전송
/// </summary>
/// <param name="clientSession"></param>
public static void SendPlayerInventory(ClientSession clientSession)
{
int PlayerUniqueId = clientSession.MyPlayer.PlayerInfo.PlayerUniqueId;
S_RespondPlayerGameData s_RespondPlayerGameData = new S_RespondPlayerGameData();
// 인벤토리 정보 가져오기
DataTableReader inventoryInfo = MySqlManager.Select($"select item_id, amount from inventory where user_id = {PlayerUniqueId}");
while (inventoryInfo.Read())
{
int item_id = Convert.ToInt32(inventoryInfo["item_id"]); // item_id 열 값 가져오기
int amount = Convert.ToInt32(inventoryInfo["amount"]); // amount 열 값 가져오기
// DbItemData 객체 생성 및 값 할당
DbItemData itemData = new DbItemData()
{
EntityCode = item_id,
Count = amount,
};
// DbItemDatas 추가
s_RespondPlayerGameData.InventoryInfo.Add(itemData);
}
DataTableReader expInfo = MySqlManager.Select($"select exp, lv from level where user_id = {PlayerUniqueId}");
if (expInfo.Read())
{
s_RespondPlayerGameData.Exp = expInfo.GetInt32(0);
s_RespondPlayerGameData.Level = expInfo.GetInt32(1);
}
else
Logger.Log($"uniqueId {PlayerUniqueId} is null from DB!");
DataTableReader coinInfo = MySqlManager.Select($"select coins, skill_point from balance where user_id = {PlayerUniqueId}");
if (coinInfo.Read())
{
s_RespondPlayerGameData.Coins = coinInfo.GetInt32(0);
s_RespondPlayerGameData.SkillPoint = coinInfo.GetInt32(1);
}
else
Logger.Log($"uniqueId {PlayerUniqueId} is null from DB!");
// 데이터 전송
clientSession.Send(s_RespondPlayerGameData);
// 할당 인벤토리 데이터 전송
SendAllocatedInventorySelf(clientSession);
}
- 위 코드는 플레이어의 인벤토리 정보를 전달하기 위한 메서드입니다.
- Select 쿼리를 사용하여 DB에서 정보를 읽고, 이를 추출하여 패킷에 담아 보냅니다.
🕹️ Unity Affiliate
- Unity Affiliate Program 파트너로서 아래의 배너를 통해 접속하신 경우 수수료를 받을 수 있습니다.
- 아래 배너의 에셋들은 '실시간 무료 에셋 랭킹'을 나타냅니다.
'unity game modules' 카테고리의 다른 글
[유니티] Graphics device is null. 오류 해결 (0) | 2024.01.18 |
---|---|
[유니티] 피해 효과 (Damage effect overlay) (0) | 2023.08.28 |
[유니티] 퀘스트 시스템(5) - 풀사이즈 UI (0) | 2023.04.11 |
[유니티] 퀘스트 시스템(4) - 컴팩트 UI (0) | 2023.04.11 |
[유니티] 퀘스트 시스템(3) - 콘텐츠 매니저 (0) | 2023.04.11 |