使用PhotonServer和Unity建立一个棋牌类游戏实例(二)构建photon服务器与数据库的交互
上一章我们建立了服务器的基础架构,而我们的账号信息什么的需要有储存的地方,我们选用MYSQL数据库进行数据处理以及储存。
1、下载、安装、配置mysql数据库
A、下载
mysql数据下载地址在http://www.mysql.com/,我们找到MySQL Community Edition版本下载,就是社区版本。建议下载安装程序,他会安装MYSQL的驱动等,避免驱动错误。
然后在下载一个叫做mysqlfront的管理工具,可以使用他建立SQL表格、字段等,可以在www.mysqlfront.de网站免费下载到。
B、安装和配置
mysql安装的时候选择cusum模式,取消其他选择,只安装mysql server for x86或者for64。然后设定tcp/ip的端口号,一定要记住了。然后就是用户权限设置,设定好数据库管理员的密码,也就是root账号的密码。最后需要设置windows的服务名字,也就是说mysqlserver在电脑的服务管理中的名字,我们这里设置他为myPhotonServer。安装完成后就可以在我的电脑-管理-服务和应用管理-服务中找到myPhotonServer,也就是我们sql的服务器,他是以windows服务的形式存在的。将这个服务设置为手动启动,启动他就可以了,下次重启电脑也要记得启动它,否则就无法访问数据库哦!
OK,下面安装mysqlfront。直接下一步下一步安装就好。然后启动mysqlfront,新建-输入名称(自己取一个),IP地址,我们是同机器安装,就输入127.0.0.1,端口就设置为你安装MySQL时候设置的端口就好。密码也一样。设置好以后确定,然后选择打开刚刚建立的连接,这样就可以按到你的sql数据库的内部结构了。记得一定要启动windows的服务哦,否则就无法访问的。进入数据库后,我们可以看到里面有几个数据库是初始生成的,我们不要管他们。
2、建立我们的数据库和表结构
A、下面建立我们的数据库
右键点击mysqlfront软件中的127.0.0.1的根目录,选择新建-数据库,名称叫做ilovepaohuzi。这个数据库就是为我们的ILovePaoHuZi游戏服务器的数据库了。
B、建立我们需要的表结构
我们的游戏需要注册、登录、还有记录玩家的信息,那么我们至少需要一个表单记录用户名和密码以及昵称等信息,我们在ilovepaohuzi数据库下面建立一个表格,叫做userinfo的表格。这个表格需要新建3个字段,一个是用户名,我们使用手机号码注册,所以他们11位字符(varchar)的,一个是密码,他是string结构的选择(varchar),还有一个昵称他也是string结构的选择(varchar)。当然你还可以增加其他字段,例如邮箱地址等。
好了,第一张表建立好了,然后我们还需要建立一张表格用来储存用户上传的图片信息作为头像
这张表就叫做image好了,它需要2个字段,1个是用户ID字段,使用int格式,代表他是属于哪个用户的,还有一个是头像字段,里面储存有一张图片,格式选用MEDIUMBLOB,它一张图片最大16M。然后添加用户ID为副索引。并建立约束将用户ID与userinfo的ID建立约束。
对了,突然想到在userinfo里面再建立3个字段,1个是胜利场数,一个是失败的场数,1个是消费点数(就是还剩下多少消费点数)。都是int格式。然后再建立3个字段,省、市、县区。可以获得其地址,方便今后进行语音的扩展。
这是数据库的结构图
注意:这个图的最后一个字段应该是县区,而不是区县,请改过来!否则后面读取数据库会出错;
这个是image表格的结构图
最后就是userinfo的结构图
好了,数据库我们建立完毕,下面开始编写我们的服务器与数据库之间的交互脚本。
3、编写服务器与数据库的交互
打开VS-ilovepaohuzi工程,下面我们需要添加引用2个操作数据库的类文件,一个是NHibernate,一个是NHibernate的扩展类FluentNHibernate。我们的photo要通过他们2个来对数据库进行操作。
3.1、NHibernate和FluentNHibernate的类文件的引用
在Vs的资源管理器的工程名上点击右键,选择管理NuGet 程序包,然后选择浏览,输入NHibernate。可以在下面的里面里面找到NHibernate和FluentNHibernate。选择他们然后再右边选择安装。2个都安装好后就可以了。可以在工程的引用下面找到他们2个的名字。
3.2、建立操作数据库的管理的类
我们的服务器要调用mysql数据库里面的数据,需要一个专门的类来进行与数据库的连接,我们在工程下建立一个新文件夹,叫做DB,里面用来储存跟数据库交互的管理类;
3.2.1、以新线程的方式去操作数据库,避免主线程卡死,建立生成线程的类:
新建项目-类-NHibernateHelper,修改这个类修饰符为public方便其他类调用他,这个类的作用是生成一个线程,今后我们查询数据库就需要在这个新的线程中对数据库进行操作。编写代码如下,照抄就好,红字部分记得修改:
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ILovePaoHuZi.DB
{
public class NHibernateHelper
{
private static ISessionFactory sessinFactory = null;
private static void 构造sessinFactory()
{
//这个太复杂了,到时候抄就好了,不解释了,我也不动,反正就是建立一个ISessionFactory接口,
//除了MYSQL COM还要下载安装mysql-connector-net
sessinFactory = Fluently.Configure().Database(MySQLConfiguration.Standard.ConnectionString(db => db.Server("127.0.0.1").Database("ilovepaohuzi").Username("root").Password("hmok383838"))).Mappings(x => x.FluentMappings.AddFromAssemblyOf()).BuildSessionFactory();
}
//构造函数
private static ISessionFactory SessinFactory
{
get
{
//如果静态函数是空,则建立一个sessinFactory
if (sessinFactory == null) 构造sessinFactory();
return sessinFactory;
}
}
///
/// 建立一个数据连接并为他打开一个ISession接口
///
///
public static ISession OpenSessin()
{
return SessinFactory.OpenSession();
}
}
}
3.2.2、建立面对数据库userinfo表结构的model类
每一个数据库表格都必须有一个对应的model类,而这些类不仅服务器要用到,在今后的客户端也要用到,所以我们在VS中还要建立一个工程,里面储存有服务器和客户端共用的一些类。在资源管理选择解决方案,右键新建项目,名字叫做ILovePaoHuZiCommon的类库项目。然后删除默认生成的class1;在ILovePaoHuZiCommon下新添加一个文件夹,叫做model。在其下面建立一个叫做UserInfo_Model的类,这个类用来作为数据库userinfo表格的映射类,以后用来储存数据库读出来的数据。记得类的修饰为public,不然其他类就调用不了它。
根据表结构来构建这个类:
namespace ILovePaoHuZiCommon.model
{
public class UserInfo_Model
{
public virtual int userID { set; get; }
public virtual string 用户名 { set; get; }
public virtual string 密码 { set; get; }
public virtual string 昵称 { set; get; }
public virtual int 胜利场数 { set; get; }
public virtual int 失败场数 { set; get; }
public virtual int 消费点数 { set; get; }
public virtual string 省名 { set; get; }
public virtual string 市 { set; get; }
public virtual string 县区 { set; get; }
}
}
3.2.4、建立面对数据库userinfo表结构的映射关系类
至于如果告诉服务器数据库的哪个字段对应UserInfo_Model类的哪个字段,那么我们也就需要一个记录有映射关系的类。
在服务器工程的DB下建立一个DBMapping文件夹,专门用来存放这些映射关系的类。
首先在这个文件夹下我们建立UserInfo_Model的映射关系类库UserInfo_Mapping:
using FluentNHibernate.Mapping;
using ILovePaoHuZiCommon.model;
namespace ILovePaoHuZi.DB.DBMapping
{
class UserInfo_Mapping: ClassMap//这里代表要映射的类的名字
{
public UserInfo_Mapping()
{//这里的X指的是一个实例化的UserInfo_Model表格类
Id(x => x.userID).Column("Id");//设置主键,并与数据库的字段映射
Map(x => x.用户名).Column("用户名");//设置X中的某变量与数据库中某字段的映射关系
//Column("密码")里面的字符串一定要和数据库里面的字段名相同,他可以不和userinfo里面的字段相同
Map(x => x.密码).Column("密码");
Map(x => x.昵称).Column("昵称");
Map(x => x.胜利场数).Column("胜利场数");
Map(x => x.失败场数).Column("失败场数");
Map(x => x.消费点数).Column("消费点数");
Map(x => x.省名).Column("省名");
Map(x => x.市).Column("市");
Map(x => x.县区).Column("县区");
Table("userinfo");//告诉程序我要建立映射关系的数据库表的名字
}
}
}
3.2.5、建立面对数据库UserInfo表结构的管理类
好了,我们现在储存数据的类有了,代表映射关系的类也有了,生成新线程的类也有了,下面我们就可以编写一个管理类型的类,用来读取、写入数据库。以后我们就可以按照这个原理去操作数据库了:生成新的线程(NHibernateHelper类)-使用表格管理类读取数据库(马上要建立的UserInfo_Manager类)-按照映射关系类(UserInfo_Mapping)的规定-储存数据到数据表的MODEL类(UserInfo_Model)。
这个类也是分别对应不同的数据库表有不同的类。我们在ILovePaoHuZi的DB文件夹下再建立一个DBManager的文件夹,专门用来放各种数据库表的操作类,建立类库UserInfo_Manager,然后开始编写需要的方法,例如,获取全部用户,查找用户名返回数据,查找昵称是否被占用,添加新用户,修改用户数据等方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ILovePaoHuZiCommon.model;
using ExitGames.Logging;
namespace ILovePaoHuZi.DB.DBManager
{
public class UserInfo_Manager
{
private static readonly ILogger log = ExitGames.Logging.LogManager.GetCurrentClassLogger();//定义log输出的接口
///
/// 查询SQL服务器中NHibernateHelper规定的数据库(ilovepaohuzi)
/// 中UserInfo_Model对应的映射关系的表中的数据,并返回一个list,
/// 如果list返回成功代表查询成功,如果返回null就表示查询失败
///
///
///
public List 获取全部用户列表()
{
try
{
using (var sessin = NHibernateHelper.OpenSessin())
//先开始建立 查询线程这个NHibernateHelper中就已经规定了数据库为ilovepaohuzi
{
using (var trsan = sessin.BeginTransaction())//使用线程开始办理事务(开始工作)
{
//这个方法会自动寻找UserInfo_Model的映射关系类,还记得 class UserInfo_Mapping : ClassMap这一段吗?
var dateList = sessin.QueryOver();//将查询结果放入UserInfo_Model为类型一个接口中,并赋予变量
trsan.Commit();//结束这个事务
return dateList.List().ToList();//返回接口中的数据生成的LIST
}
}
}
catch(Exception e)
{
//将错误代码输出到log中去
log.Debug("UserInfo_Manager中 (获取全部用户列表) 方法出错:"+e);
return null;
}
}
///
/// 使用用户名查询用户数据,返回的结果为null代表查询出错,结果为LIST为查询成功
/// list的数量为0表示没有这个用户,数量》=1表示有这个用户
///
///
///
public List 查询某用户_根据用户名(string username)
{
try
{
using (var sessin = NHibernateHelper.OpenSessin())//先开始建立 查询线程
{
using (var trsan = sessin.BeginTransaction())//使用线程开始办理事务(开始工作)
{
var dateList = sessin.QueryOver().Where(用户数据 => 用户数据.用户名 == username);
//以某条件查询并将查询结果放入TestUser为类型一个接口中,并赋予变量
trsan.Commit();//结束这个事务
return dateList.List().ToList();//返回接口中的数据生成的LIST
}
}
}
catch (Exception e)
{
//将错误代码输出到log中去
log.Debug("UserInfo_Manager中 (查询某用户_根据用户名) 方法出错:" + e);
return null;
}
}
///
/// 建立新的用户,如果相同则返回-1,建立出错返回-2,建立成功则返回这个用户分配的ID号
///
///
///
public int 用户注册(UserInfo_Model 用户注册信息)
{
try
{
//要保证 用户注册信息 的数据符合服务器的格式,例如,我们的ID项目是7位数的int,如果他是8位数的数字就会出错
using (var sessin = NHibernateHelper.OpenSessin())//先开始建立 查询线程
{
using (var trsan = sessin.BeginTransaction())//使用线程开始办理事务(开始工作)
{
//先查询表里有没有相同的用户名,如果有的话则返回-1;
IList 查询结果 = 查询某用户_根据用户名(用户注册信息.用户名);
if (查询结果 == null) return (-2);
if (查询结果.Count > 0) return (-1);
//如果没有同名的则存储新用户,并返回新用户的ID号
sessin.Save(用户注册信息);
trsan.Commit();//结束这个事务
return 用户注册信息.userID;
}
}
}
catch (Exception e)
{
//将错误代码输出到log中去
log.Debug("UserInfo_Manager中 (用户注册) 方法出错:" + e);
return -2;
}
}
///
/// 修改用户资料,需要提供的用户资料的ID和用户名匹配,返回-1为ID和用户名不匹配,或者用户不存在。返回-2为服务器错误,返回0为修改成功
///
///
///
public int 修改用户资料(UserInfo_Model 修改后的用户资料)
{
try
{
//先检查用户ID和用户名是否正确
using (var sessin = NHibernateHelper.OpenSessin())//先开始建立 查询线程
{
using (var trsan = sessin.BeginTransaction())//使用线程开始办理事务(开始工作)
{
//先查询表里有没有相同的用户名,如果有的话则返回-1;
IList 查询结果 = 查询某用户_根据用户名(修改后的用户资料.用户名);
//如果没有这个用户或者用户名和ID不同,则返回-1;代表没有这个用户
//如果查询错误则返回-2
if (查询结果 == null) return (-2);
if (查询结果.Count <= 0) return (-1);
if (查询结果.Count > 0&& 修改后的用户资料.userID!= 查询结果[0].userID) return (-1);
//如果查询结果正常,则开始更新用户数据
sessin.Update(修改后的用户资料);
trsan.Commit();//结束这个事务
return 0;
}
}
}
catch (Exception e)
{
//将错误代码输出到log中去
log.Debug("UserInfo_Manager中 (修改用户资料) 方法出错:" + e);
return -2;
}
return -2;
}
}
}
OK!用户登录表格的任务已经完成,然后下面照着上面去完成用户头像表格的交互。我就直接发代码,你们自己来哦……
3.2.6、建立面对数据库imager表结构的model类
namespace ILovePaoHuZiCommon.model
{
class Image_Model
{
public virtual int ID { set; get; }
public virtual int 用户ID { set; get; }
public virtual byte[] 头像 { set; get; }
}
}
3.2.7、建立面对数据库imager表结构的映射关系类
using FluentNHibernate.Mapping;
using ILovePaoHuZiCommon.model;
namespace ILovePaoHuZi.DB.DBMapping
{
class Image_Mapping: ClassMap
{
public Image_Mapping()
{
Id(x => x.ID).Column("Id");//设置主键,并与数据库的字段映射
Map(x => x.用户ID).Column("用户ID");//设置X中的某变量与数据库中某字段的映射关系
Map(x => x.头像).Column("头像");
Table("image");//告诉程序我要建立映射关系的数据库表的名字
}
}
}
3.2.8、建立面对数据库imager表结构的管理类
using System;
using System.Collections.Generic;
using System.Linq;
using ILovePaoHuZiCommon.model;
using ExitGames.Logging;
namespace ILovePaoHuZi.DB.DBManager
{
class Image_Manager
{
private static readonly ILogger log = ExitGames.Logging.LogManager.GetCurrentClassLogger();//定义log输出的接口
///
/// 使用用户ID查询用户数据,返回的结果为null代表查询出错,结果为LIST为查询成功
/// list的数量为0表示没有这个用户,数量》=1表示有这个用户
///
///
///
public List 查询某用户_根据用户ID(int userID)
{
try
{
using (var sessin = NHibernateHelper.OpenSessin())//先开始建立 查询线程
{
using (var trsan = sessin.BeginTransaction())//使用线程开始办理事务(开始工作)
{
var dateList = sessin.QueryOver().Where(用户数据 => 用户数据.用户ID == userID);
//以某条件查询并将查询结果放入TestUser为类型一个接口中,并赋予变量
trsan.Commit();//结束这个事务
return dateList.List().ToList();//返回接口中的数据生成的LIST
}
}
}
catch (Exception e)
{
//将错误代码输出到log中去
log.Debug("Image_Manager中 (查询某用户_根据用户ID) 方法出错:" + e);
return null;
}
}
///
/// 修改用户资料,需要提供的用户资料的ID和用户名匹配,返回-1为ID和用户名不匹配,或者用户不存在。返回-2为服务器错误,返回0为修改成功
///
///
///
public int 修改用户头像(Image_Model 修改后的用户头像资料)
{
try
{
//先检查用户ID和用户名是否正确
using (var sessin = NHibernateHelper.OpenSessin())//先开始建立 查询线程
{
using (var trsan = sessin.BeginTransaction())//使用线程开始办理事务(开始工作)
{
//先查询表里有没有相同的用户名,如果有的话则返回-1;
IList 查询结果 = 查询某用户_根据用户ID(修改后的用户头像资料.用户ID);
//如果没有这个用户或者用户名和ID不同,则返回-1;代表没有这个用户
//如果查询错误则返回-2
if (查询结果 == null) return (-2);
if (查询结果.Count <= 0) return (-1);
修改后的用户头像资料.ID = 查询结果[0].ID;
//如果查询结果正常,则开始更新用户数据
sessin.Update(修改后的用户头像资料);
trsan.Commit();//结束这个事务
return 0;
}
}
}
catch (Exception e)
{
//将错误代码输出到log中去
log.Debug("Image_Manager中 (修改用户头像) 方法出错:" + e);
return -2;
}
return -2;
}
}
}