虽然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 = 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);

MySQL 存储过程实例 与 ibatis/mybatis/hibernate/jdbc 如何调用存储过程的更多相关文章

  1. iBatis & myBatis & Hibernate 要点记录

    iBatis & myBatis & Hibernate 要点记录 这三个是当前常用三大持久层框架,对其各自要点简要记录,并对其异同点进行简单比较. 1. iBatis iBatis主 ...

  2. jdbc中的Statement对象和Preparedstatement对象的区别,以及通过jdbc操作调用存储过程

    一. java.sql.*   和  javax.sql.*的包的类结构 |- Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接口. |- connect(url, p ...

  3. MyBatis学习总结(六)——调用存储过程(转载)

    本文转载自:http://www.cnblogs.com/jpf-java/p/6013518.html 一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存 ...

  4. MyBatis入门学习教程-调用存储过程

    一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 create table p_user( id int primary key auto_incr ...

  5. MyBatis学习总结(六)——调用存储过程

    一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 1 create table p_user( 2 id int primary key auto_ ...

  6. MyBatis学习总结(六)——调用存储过程

    一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 create table p_user( id int primary key auto_incr ...

  7. MyBatis学习总结_06_调用存储过程

    一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 1 create table p_user( 2 id int primary key auto_ ...

  8. MyBatis学习笔记(六)——调用存储过程

    转自孤傲苍狼的博客:http://www.cnblogs.com/xdp-gacl/p/4270352.html 一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据 ...

  9. 六:MyBatis学习总结(六)——调用存储过程

    一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 create table p_user( id int primary key auto_incr ...

随机推荐

  1. SQL语句技巧:查询存在一个表而不在另一个表中的数据记录

    方法一(仅适用单个字段)使用 not in ,容易理解,效率低 select A.ID from A where A.ID not in (select ID from B) 方法二(适用多个字段匹配 ...

  2. Java魔法堂:String.format详解

      目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六.对浮点数进行格式化     七.对日期时间进行格式化 ...

  3. Java魔法堂:自定义和解析注解

    一.前言 注解(Annotation)作为元数据的载体,为程序代码本身提供额外的信息,使用过MyBatis等ORM框架的朋友对 @Insert 的注解应该不陌生了,这是MyBatis自定义的注解,显然 ...

  4. CMD魔法堂:获取进程路径和PID值的方法集

    一.前言    在开发发布更更新工具——更新Weblogic应用模块时,了解到更新Weblogic应用需要先关闭Weblogic应用窗口然后是清缓存.更新应用文件,最后再重启Weblogic应用窗口. ...

  5. IE11之F12 Developer Tools--概述篇

    打开Developer Tools的方法: a. 点击F12 b. 在浏览器中选择Tools-->F12 Develooper Tools 打开后图示: 从上图我们可以看到,Developer ...

  6. ThroughRain第一次冲刺个人总结

    团队名:ThroughRain 项目确定:<餐厅到店点餐系统> 项目背景:本次项目是专门为餐厅开发的一套订餐系统.大家有没有发现在节假日去餐厅吃饭会超级麻烦,人很多, 热门的餐厅基本没有座 ...

  7. 快速暴力解决Eclipse ADT和Android Studio兼容问题,创建同时兼容ADT和AS的安卓工程

    环境:AS 2.1.2+Java1.7+Gradle 2.14+ADT 24.0.2+MyEclipse 2015 前言:因为比赛要求使用ADT,而我本身比较习惯使用AS开发,遂想办法打造兼容两个ID ...

  8. 关于 getWriter() has already been called for this response 的错误解决办法

    java.lang.IllegalStateException: getWriter() has already been called for this response 今天在做显示图片的时候,( ...

  9. linq order by charindex 排序 按给定字符串顺序排序

    //list=list.OrderBy(ee => SqlFunctions.CharIndex("书记,主任,支部委员,村委委员,系统工作人员", ee.ZhiWu)).T ...

  10. linux系统如何将系统中的文件名改为英文?

    由于我们经常在命令行模式下进入文件,那么中英文的切换常常会影响我们输入的效率. 那么如何将原来的中文修改成英文的字幕呢? 如下图所示: -------------------------------- ...