MySQL 存儲過程實例 與 ibatis/mybatis/hibernate/jdbc 如何調用存儲過程

雖然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 = 1UNTIL 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);
相關文章
相關標籤/搜索