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


雖然MySQL的存儲過程,一般情況下,是不會使用到的,但是在一些特殊場景中,還是有需求的。最近遇到一個sql server向mysql遷移的項目,有一些sql server的存儲過程需要向mysql遷移。所以進行復習了一下。下面是一些存儲過程的例子。

1. 例子1

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 ;

知識點

1)參數分為 in, out 類型,即輸入類型和輸出類型;

2)select xx into varible from table where ... 句式:

     SELECT COUNT(*) INTO cnt FROM Users u WHERE u.user_MobileCode=user_MobileCode;

3)if cnt > 0 then ... elseif cnt =0 then ... else ... end if;

    if 語句注意帶有 then 關鍵字和 end if 結束關鍵字。

4)獲取 insert 語句的主鍵set userId=last_insert_id(); select userId;

   select last_insert_id() into userId; 也是可以的。

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);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM