雖然MySQL的存儲過程,通常狀況下,是不會使用到的,可是在一些特殊場景中,仍是有需求的。最近遇到一個sql server向mysql遷移的項目,有一些sql server的存儲過程須要向mysql遷移。因此進行復習了一下。下面是一些存儲過程的例子。java
1. 例子1mysql
DELIMITER // DROP PROCEDURE IF EXISTS loginandreg // CREATE PROCEDURE loginandreg( OUT userId BIGINT, IN user_Pwd VARCHAR(32), IN user_MobileCode VARCHAR(16), IN user_RegIP VARCHAR(16) ) BEGIN DECLARE cnt BIGINT DEFAULT 0; DECLARE cnt2 BIGINT DEFAULT 0; DECLARE outid BIGINT DEFAULT -1; SELECT COUNT(*) INTO cnt FROM Users u WHERE u.user_MobileCode=user_MobileCode; IF cnt > 0 THEN SELECT COUNT(*) INTO cnt2 FROM Users u WHERE u.user_MobileCode=user_MobileCode AND u.user_Pwd=user_Pwd; IF cnt2 > 0 THEN SELECT u.userId INTO outid FROM Users u WHERE u.user_MobileCode=user_MobileCode AND u.user_Pwd=user_Pwd LIMIT 1; ELSE SELECT -1 INTO outid; END IF; SELECT outid INTO userId; ELSE INSERT INTO Users(user_Pwd,user_MobileCode,user_Visibility,user_Level,user_RegTime,user_RegIP,
user_Collecter,user_Collected) VALUES (user_Pwd,user_MobileCode,6,6,NOW(),user_RegIP,0,0); SET userId=LAST_INSERT_ID(); SELECT userId; END IF; END // DELIMITER ;
知識點:sql
1)參數分爲 in, out 類型,即輸入類型和輸出類型;session
2)select xx into varible from table where ... 句式:mybatis
SELECT COUNT(*) INTO cnt FROM Users u WHERE u.user_MobileCode=user_MobileCode;app
3)if cnt > 0 then ... elseif cnt =0 then ... else ... end if;ide
if 語句注意帶有 then 關鍵字和 end if 結束關鍵字。函數
4)獲取 insert 語句的主鍵:set userId=last_insert_id(); select userId;優化
select last_insert_id() into userId; 也是能夠的。this
5)mysql客戶端 如何調用該存儲過程:
CALL loginandreg(@userId,'123456','18357xxx7','127.0.0.1');
SELECT @userId;
最後的 select @userId 就是存儲過程的 out 類型參數返回的結果。
6) 上面的例子,還能夠使用 if exists ( select from ...) 語句和 FOUND_ROWS() 函數 來優化一下:
DELIMITER // DROP PROCEDURE IF EXISTS loginandreg // CREATE PROCEDURE loginandreg( OUT userId BIGINT, IN user_Pwd VARCHAR(32), IN user_MobileCode VARCHAR(16), IN user_RegIP VARCHAR(16) ) BEGIN IF EXISTS(SELECT * FROM Users u WHERE u.user_MobileCode=user_MobileCode) THEN SELECT u.userId INTO userId FROM Users u WHERE u.user_MobileCode=user_MobileCode AND u.user_Pwd=user_Pwd; IF FOUND_ROWS() < 1 THEN SELECT -1 INTO userId; END IF; ELSE INSERT INTO Users(user_Pwd,user_MobileCode,user_Visibility,user_Level,user_RegTime,user_RegIP,
user_Collecter,user_Collected) VALUES (user_Pwd,user_MobileCode,6,6,NOW(),user_RegIP,0,0); SELECT LAST_INSERT_ID() INTO userId; END IF; END // DELIMITER ;
2. 例子2
DELIMITER // DROP PROCEDURE IF EXISTS mingRenTangJiangLi // CREATE PROCEDURE mingRenTangJiangLi() BEGIN DECLARE total_level,role_id,ming_ren_level,ming_ren_type, fuben_times,tiaozhan_times,duobei_shijian,no_more_data INT DEFAULT 0; DECLARE my_cursor CURSOR FOR SELECT playerRoleId,`level`,type from mingrentang; DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_data = 1; OPEN my_cursor; FETCH my_cursor INTO role_id,ming_ren_level,ming_ren_type; REPEAT set total_level = ming_ren_level + 10 * (ming_ren_type-1); set fuben_times = total_level / 2; set tiaozhan_times = total_level /3; set duobei_shijian = 10 * total_level; select total_level,fuben_times,tiaozhan_times,duobei_shijian; update player_role set hufu=hufu+1000,paihangbangNumber=paihangbangNumber+tiaozhan_times, duobeiShiJian=duobeiShiJian+duobei_shijian,fubenTimes=fubenTimes+fuben_times; FETCH my_cursor INTO role_id,ming_ren_level,ming_ren_type; UNTIL no_more_data = 1 END REPEAT; CLOSE my_cursor; END // DELIMITER ;
知識點:
1)該例子演示了遊標的用法:
DECLARE my_cursor CURSOR FOR SELECT playerRoleId,`level`,type from mingrentang; DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_data = 1;
定義了遊標語句,也說明了遊標循環結束時設置的標誌:SET no_more_data = 1;
OPEN my_cursor; FETCH my_cursor INTO role_id,ming_ren_level,ming_ren_type;
打開遊標,從遊標中獲取值。
REPEAT
......
FETCH my_cursor INTO role_id,ming_ren_level,ming_ren_type; UNTIL no_more_data = 1 END REPEAT;
repeat 循環 直到 no_more_data = 1: UNTIL no_more_data = 1,而後結束循環 END REPEAT;
最後關閉遊標 close my_cursor;
由於上面在定義遊標時,指明瞭,沒有數據時設置了 no_more_data = 1,因此這裏使用 UNTIL no_more_data = 1 來退出repeat
2)判斷相等是使用 = ,而不是 == ,賦值操做是使用 set var=xxx; :set fuben_times = total_level / 2;
3)循環: repeat ... until ... end repeat;
3. Java 如何調用存儲過程
1)hibernate調用存儲過程:
/* * 調用無參數的存儲過程,傳入存儲過程名字 */ public int callProcedure(final String procedureName) { int count = (Integer)this.getHibernateTemplate().execute( new HibernateCallback(){ public Object doInHibernate(Session session) throws HibernateException, SQLException { String procedureSql = "{call "+ procedureName +"()}"; Query query = session.createSQLQuery(procedureSql); Integer num = query.executeUpdate(); return num; } }); return count; }
2)ibatis 調用mysql 存儲過程:
@Override public Long loginAndRegByProcedure(String user_Pwd, String user_MobileCode, String user_RegIP){ Long userId = null; HashMap<String,Object> paramMap = new HashMap<String,Object>(); paramMap.put("userId", userId); paramMap.put("user_Pwd", user_Pwd); paramMap.put("user_MobileCode", user_MobileCode); paramMap.put("user_RegIP", user_RegIP); this.getSqlMapClientTemplate().queryForObject("Users.loginAndRegByProcedure", paramMap); return (Long)paramMap.get("userId"); }
對應的xml 文件配置:
<parameterMap id="pro_pram_Map" class="java.util.Map"> <parameter property="userId" javaType="java.lang.Long" jdbcType="BIGINT" mode="OUT"/> <parameter property="user_Pwd" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/> <parameter property="user_MobileCode" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/> <parameter property="user_RegIP" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/> </parameterMap> <procedure id="loginAndRegByProcedure" parameterMap="pro_pram_Map"> {call loginandreg(?, ?, ?, ?)} </procedure>
存儲過程的參數的類型,是在xml文件中說明的。
3) JDBC 調用mysql 存儲過程:
public Long loginAndRegByProcedure2(String user_Pwd, String user_MobileCode, String user_RegIP){ Connection conn = DbUtil.getConnection(); CallableStatement cstmt = conn.prepareCall("{call loginandreg(?, ?, ?, ?)}"); cstmt.setString(2, user_Pwd); cstmt.setString(3, user_MobileCode); cstmt.setString(4, user_RegIP); cstmt.registerOutParameter(1, java.sql.Types.BIGINT); cstmt.execute(); return cstmt.getLong(1); }
輸入參數:cstmt.setString(2, user_Pwd);
輸出參數:cstmt.registerOutParameter(1, java.sql.Types.BIGINT);
4)mybatis 調用mysql存儲過程:
mapper 接口
public interface UserMapper { Long loginAndRegByProcedure(Map<String, Object> param);
xml 配置文件
<select id="loginAndRegByProcedure" parameterType="java.util.Map" statementType="CALLABLE" resultType="long"> {call loginandreg( #{userId,jdbcType=BIGINT,mode=OUT}, #{user_Pwd,jdbcType=VARCHAR,mode=IN}, #{user_MobileCode,jdbcType=VARCHAR,mode=IN}, #{user_RegIP,jdbcType=VARCHAR,mode=IN} ) } </select>
注意: statementType="CALLABLE" resultType="long" 和 mode=OUT
service 層調用mapper接口:
Long userId = null; HashMap<String,Object> paramMap = new HashMap<String,Object>(); paramMap.put("userId", userId); paramMap.put("user_Pwd", user_Pwd); paramMap.put("user_MobileCode", user_MobileCode); paramMap.put("user_RegIP", user_RegIP);
userId=userMapper.loginAndRegByProcedure(map);