春节小长假一放完,自己都还没有来得及见见同学什么的,公司要求开始上班了。
今年过年的事情就不再说了,对于公司离家还是不太远的我倒是没有什么影响,虽然每次回家都要花上4、5个小时。
初八开始上班,刚刚放完假回来完全是没有动力去创造价值,磨磨的就把来的两天过了。
第二周,自己仿佛又回到了完美的工作状态,虽然自己的效率是有点低,但是还是学到了很多东西。
处理了几个业务,也练习了自己的能力。
虽然业务都是mssql的特殊数据查询,但是我还是做的津津有味。特别是那个多条件链接的查询,把我坑的说不出话来。废话不多说直接来代码:
SELECT
TABLE2.PlatName,
TABLE1.*
FROM
(SELECT
A.GameID,
A.PlatID,
A.ServerID,
A.Date,
isnull (A.Points,0) AS "充值总点数",
isnull (A.PayNum,0) AS "充值人数",
isnull (B.BuyPoint,0) AS "消费总点数",
isnull (B.BuyNum,0) AS "消费人数"
FROM
(SELECT
GameID,
PlatID,
ServerID,
convert(varchar(10),[PayTime],120) AS Date,
SUM(BasePoints) AS Points,
COUNT(DISTINCT UserID) AS PayNum
FROM [库1].[Account].[dbo].[ChargeLog]
WHERE GameID=16 --xb
AND PayTime BETWEEN '2014-01-01 00:00:00.000' AND GETDATE()
GROUP BY GameID,PlatID,ServerID,convert(varchar(10),[PayTime],120)) as a
FULL JOIN
(SELECT
[GameID],[ServerID]
,convert(varchar(10),[BuyTime],120) AS Date,
-SUM([BuyPoint]) AS BuyPoint,
COUNT(DISTINCT UserID) AS BuyNum
FROM [库1].[Account].[dbo].[PlayerBuyLog]
WHERE GameID=16 --xb
AND PointType=0
AND [BuyTime] BETWEEN '2014-01-01 00:00:00.000' AND GETDATE()
GROUP BY [GameID],ServerID,convert(varchar(10),[BuyTime],120)) as b
ON
a.GameID=B.GameID
AND A.ServerID=B.ServerID
AND A.Date=B.Date )
AS TABLE1
INNER JOIN
(SELECT * FROM [库2].[PlatInfo].[dbo].[tb_Plat])
AS TABLE2
ON TABLE1.PlatID=TABLE2.PlatID
ORDER BY TABLE1.PlatID,TABLE1.ServerID,TABLE1.Date
目的很简单的,就是两个结果集做个连接就好了。但是这个存储过程却是有问题的,连接条件几个的时候是有误的。我这里上面一个查询单查出来是79条记录,下面一个是39条作全连接记录变成了37条,不知道有没有做DBA的同学遇到过。问题先记录在这儿吧。
还是说正文,这篇文章是说mysql存储过程的:
在去年年末的时候开始接触mysql存储过程,因为以前用mysql好像都没有在意用存储过程。
提供了事务性和非事务性存储引擎,这是mysql的特点,以前都用的是MyISAM引擎。
大家也看到了,mysql提供多种拉风的存储引擎,大家有兴趣可以去百度、google一下。对于各种引擎介绍我也就不说了,因为是要存储过程就得支持事务了额,那我们就得说说MyISAM和InnoDB了,这两个是mysql极为常见使用的存储引擎。
可能有的同学还没有关心这个,因为以前都是默认的,默认是MyISAM引擎,这个是一个高速存取的数据库引擎,不支持事务。然后事务作为存储过程的一个亮点,显然MyISAM引擎此时就没有了发挥的空间了。自3.23.49版以来,InnoDB事务存储引擎一直很稳定。InnoDB正用于大型、重负荷生产系统。InnoDB是MySQL 5.x版本频繁支持的,既然开始支持了,这一个分支的发展也就快了起来,但是官方发布的MySQL版本好像对存储过程的开发做的并不像mssql做的那么好。以至于好多的开发者不愿意使用mysql的存储过程。事实上,mysql的存储过程比起mssql,应该说只有更好没有差的。因为mssql为开发者做的太多了,反而限制了开发者的发挥。
现在公司准备向手游转型,数据库支持换mysql,虽然我是菜鸟也得硬着头皮搞额。
首先,mysql中几乎没有什么高级的函数,基本上所有的东西都要自己写。
这个给我带来一些问题的,mssql许多的特色函数都没有了,mysql只提供了一些基本的。
比如:
mssql提供的ISNUMERIC函数
mysql中我是没有找到有相关的函数可以解决的,后来还是通过自己到MySQL AB的一个论坛上找到了大牛写的源码:
CREATE DEFINER = `root`@`127.0.0.1` FUNCTION `fn_IsNumeric`(myVal VARCHAR(1024))
RETURNS tinyint(1)
DETERMINISTIC
RETURN myVal REGEXP '^(-|\\+)?([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';
其实我想说,没有的我们都可以写,不要怕。mysql数据库一样的出色。
还有mssql中的GetDate()莫名被换成了Now(),DateTime类型和TimeStamp类型区别啊......
做mysql数据库有太多的创新点要我们开发者自己去做去实践,而不是等着别人更新版本然后就只是去体验新功能然后再用什么的。要能做到我们需要什么东西就做什么,也许你做的以后指不定就成为了标准了,这不是一件很自豪的事情么。
DROP PROCEDURE IF EXISTS sp_AccountVerify;
CREATE DEFINER=`root`@`%` PROCEDURE sp_AccountVerify
(
IN v_Account varchar(50), -- 登陆账号
IN v_Password varchar(32), -- 登陆密码
IN v_ServerID int, -- 服务器编号
IN v_PlayerIP varchar(20), -- 玩家登陆IP
IN v_IsLimited int, -- 是否受限
IN v_MacAddress bigint, -- 客户端MAC地址
OUT ov_PlayerUID bigint, -- 账号唯一编号
OUT ov_CardPoint int, -- 剩余元宝
OUT ov_GMLevel smallint, -- M等级
OUT ov_UserPassword varchar(20), -- 玩家二级密码
OUT ov_LoginTime timestamp, -- 登陆时间
OUT ov_IsDynamicPWD bit, -- 用户密码是否为动态密码1为是否则不是
OUT ov_ServerInfo varchar(64), -- 上次登陆服务器名字
OUT ov_RealAccount varchar(36), -- 真实账号
OUT ov_iReturnValue int -- 处理结果 ,0表示未处理
)
/*
//ov_iReturnValue = 0
//ov_iReturnValue = -1
//ov_iReturnValue = -2
//ov_iReturnValue = -3
//ov_iReturnValue = -4
//ov_iReturnValue = -5
//ov_iReturnValue = -6
//ov_iReturnValue = -7
//ov_iReturnValue > 0
//ov_iReturnValue -9
*/
BEGIN
DECLARE var_pwd varchar(32); -- 账号密码
DECLARE var_LockTime timestamp; -- 锁定时间
DECLARE var_UID bigint; -- 用户ID
DECLARE var_GameID int; -- 游戏编号
DECLARE var_UpdateTime timestamp; -- 更新时间
DECLARE var_PlatID int; -- 平台ID
DECLARE var_AllowIP varchar(200); -- GMIP
DECLARE var_RC INT;
SET ov_RealAccount = v_Account;
SET ov_CardPoint = 0;
SET ov_UserPassword = '123456';
SET ov_LoginTime = NOW();
SET ov_IsDynamicPWD = 0;
SET ov_ServerInfo = '';
SET var_UID = v_Account;
SET var_GameID = 0;
Opt_Label:
BEGIN
IF v_PlayerIP IN ('涉密数据库') THEN
SET OV_iReturnValue = -3;
LEAVE Opt_Label;
END IF;
/*获取用户登陆信息*/
SELECT UserID,GmLevel,Password,LockTime,UpdateTime,PlatID
INTO ov_PlayerUID,ov_GMLevel,var_pwd,var_LockTime,var_UpdateTime,var_PlatID
FROM UserID
WHERE UserID= var_UID;
SET var_UpdateTime = (date_add(var_UpdateTime,INTERVAL 24 DAY_HOUR));
/*用户检查*/
IF IFNULL(ov_PlayerUID,0) <= 0 THEN
SET OV_iReturnValue = -6;
LEAVE Opt_Label;
END IF;
/*GM不验证密码,玩家密码检查*/
IF IFNULL(ov_GMLevel,0) <= 0 THEN
/*动态口令过期检查*/
IF var_UpdateTime < NOW() THEN
SET OV_iReturnValue = -7;
LEAVE Opt_Label;
END IF;
IF (v_Password <> var_pwd) THEN
SET OV_iReturnValue = -7;
LEAVE Opt_Label;
END IF;
END IF;
CALL sp_CheckUserLock(var_UID,var_GameID,v_ServerID,v_PlayerIP,v_MacAddress,@var_RC);
SET var_RC = @var_RC;
IF var_RC = 1 THEN
SET OV_iReturnValue = -3;
LEAVE Opt_Label;
END IF;
/*封号检查*/
IF (var_LockTime IS NOT NULL AND var_LockTime > NOW()) THEN
SET OV_iReturnValue = -3;
LEAVE Opt_Label;
END IF;
SELECT MAX(LockTime) INTO var_LockTime FROM UserLock WHERE UserID=var_UID AND GameID=var_GameID AND (ServerID=v_ServerID or ServerID=0);
/*封号检查*/
IF(var_LockTime IS NOT NULL AND var_LockTime > NOW()) THEN
SET OV_iReturnValue = -3;
LEAVE Opt_Label;
END IF;
/*如果GM账号就要检查密码*/
IF IFNULL(ov_GMLevel,0) > 0 THEN
SELECT AllowIP INTO var_AllowIP from PlatGMIP where PlatID=var_PlatID;
IF INSTR(','+var_AllowIP+',' , ','+v_PlayerIP+',') <= 0 THEN
SET OV_iReturnValue = -6;
LEAVE Opt_Label;
END IF;
END IF;
/*主账号表检查*/
IF EXISTS(SELECT * FROM AccountData where UserID=ov_PlayerUID and GameID=var_GameID and ServerID=v_ServerID LIMIT 1) THEN
UPDATE AccountData SET LoginTime=ov_LoginTime WHERE UserID=ov_PlayerUID and GameID=var_GameID and ServerID=v_ServerID;
ELSE
INSERT INTO AccountData(UserID,GameID, ServerID, LoginTime, LastLogTime, MaxLevel, OnlineTime, FirstLoginTime, PayPoint,IsLogin)
VALUES(ov_PlayerUID,var_GameID,v_ServerID,ov_LoginTime,NULL,0,0,ov_LoginTime,0,1);
END IF;
SET OV_iReturnValue = 1;
END Opt_Label;
END
大家看看上面的存储过程写法吧,这是我推荐的写法。
作为公司数据安全有的地方就删除掉了。
在mysql中没有了@作为参数变量的说法了,@只能是用户变量,意思说你只能在调用存储过程的时候可以用。
但是我们的参数还是要有办法解决啥,我的推荐:
格式大家看我那个应该就知道了啥,主要是对于变量的处理,大家各有各的爱好这也是没有办法的,这让其他的人阅读起来带来了巨大的麻烦。希望大家都能做一个比较一致的东西出来,为开源发展继续努力。
我的书写方法也不一定就是好,大家可以提出自己的一件交流一哈:Email:jyf0412@sina.com
注意的地方就是,
1、你的存储过程得有一个执行成功与否的值
ov_iReturnValue2、在mysql中没有return一说,所以大家对return相关的东西都得改写,用标签解决。
这个标签名字大家也不要取的太奇葩,随意就行,LOOP最好。3、在存储过程内部声明的变量命名这也是一个奇葩的地方,不能用@,你让mssql的DBA如何能习惯。大家用前缀解决吧
DECLARE var_pwd varchar(32); -- 账号密码
DECLARE var_LockTime timestamp;
谨以此文,开始我的mysql DBA生涯。
或许现在大家对Oracle的数据库期望很高,的确实力也很强。
但是我是一直小小鸟,慢慢来吧。
大家有什么好的建议或者意见可以邮件我,一般每天我都能及时回复,最迟不超过一周。
一起进步吧!