您好,欢迎访问一九零五行业门户网

mybatics 中调用mysql存储过程

说起mybatics 框架,身边的java开发工程师们基本上都是耳熟能详。 mybatics是apache的一个开源项目,前身为ibatics,2010年此项目由apache软件基金会迁移到了google code,mybatics的确是一款十分优秀的开源持久层框架,sql代码隔离封装、自动pojo映射、jdbc
说起mybatics 框架,身边的java开发工程师们基本上都是耳熟能详。 mybatics是apache的一个开源项目,前身为ibatics,2010年此项目由apache软件基金会迁移到了google code,mybatics的确是一款十分优秀的开源持久层框架,sql代码隔离封装、自动pojo映射、jdbc 动态sql———— mybatics的好处可以说出一箩筐,然而mybatics还有一个十分优秀的特性却往往被人忽略 ----那就是mybatics还支持存储过程的调用。
      不熟悉存储过程的人大都觉得存储过程复杂难懂,认为既然有了dao,那么所有的对数据库操作的逻辑(crud)都放到dao层就可以了,存储过程是没有必要的。无论如何,在dao中写java代码总比在数据库中写存储过程要舒服容易的多,又何必多花费时间学习一门新的存储过程语言呢?
     的确,对于以下中小型项目而言,基本的增删改查sql操作就足以应付了(再稍微复杂点也就高级查询,也就把dao层改改弄得稍复杂点就行了)。可是做过稍大型点的项目的人(尤其是互联网方面)都知道,大项目尤其是分布式系统的互联网项目对于数据库安全、性能、稳定性都有很高的要求。 当web服务器和数据库服务器分布在不同的机器上,dao层调数据库服务器是需要很大的网络开销,sql语句必须从web服务器发送到数据库服务器再执行。可是存储过程就不同,存储过程的所有sql逻辑到存放在数据库服务器本地且执行效率非常高。而且由于dao层代码是放到本地,存储过程代码是在远程服务器中,故安全性上也比不上存储过程。至于稳定性就更不用谈了。
    幸运的是mybatics是完美支持存储过程调用的,这一点让人感到十分欣慰,也无疑更是增加了我对它的喜爱。
     对于mysql而言,mysql 5.0以后的版本是支持存储过程的 。
    下面我介绍下mybatics中如何调用mysql 存储过程,至于调用oracle 的存储过程也是大同小异的,值得注意的是当程序需要返回list集合数据出来时,oracle中需要返回游标,而mysql中直接select出去即可 。
1、 mybatics中调用mysql 存储过程返回list 列表数据。
         根据name (模糊)查询用户信息列表,返回用户列表
         usermapper.xml 中 配置  存储过程调用, 注意  statementtype=callable  ,select元素配置的ressulttype 直接就是user类型。
{call queryuserlist_namesp( #{name,jdbctype=varchar,mode=in} ) }
service 层java代码,调用mapper接口 入参传一个map,返回值是list 类型
public map getuserlistnamelike(string name) { try { map params=ajaxutil.getmap(); params.put(name, name); list userlist = usermapper.queryuserlistbylikename_sp(params); if(userlist!=null){ map map= ajaxutil.messagemap(1, 查询成功); map.put(userlist, userlist); return map; } } catch (exception e) { logger.error(e); throw new runtimeexception(e); } return ajaxutil.messagemap(-1, 查询失败); }
mapper 接口 代码,就一个接口声明(通过mybatics动态代理方式产生其实现类)
public list queryuserlistbylikename_sp( map params);
最后看下,存储过程的代码。(也很简单就一个select 模糊查询)
delimiter $$use `easyuidemo`$$drop procedure if exists `queryuserlist_namesp`$$create definer=`root`@`localhost` procedure `queryuserlist_namesp`(in in_name varchar(50))begin select * from t_user t where t.name like concat('%',in_name,'%') ; end$$delimiter ;
2、   mybatics中调用mysql 存储过程添加用户。
页面表单ajax上传的用户信息,通过存储过程完成用户添加。要求添加成功时,存储过程中要返回rc(reponsecode结果码)、msg(结果消息)、userid(新添加的用户id)
        usermapper.xml 中的配置。
       值得注意的是,这里的存储过程配置既可以配置为select节点元素,也可以配置为其它insert、update、delete元素,且无须配置resulttype 或resultmap,如果是select元素,请一定要设置usercache=“false”  。入参我这里设置为了map。(这里的map其实就是java.util.map, mybatics中内置了许多java中类型到jdbc类型的别名映射,比如java中int对应为jdbc中integer,而map就是java.util.map的在mybatics中的别名 ),大家可能会注意我这入参并没有用user  这个bean对象,用bean来传字段属性岂不是更合乎情理吗? 这个稍候再跟大家解释下。。。
{call adduser_sp( #{name,jdbctype=varchar,mode=in}, #{age,jdbctype=integer,mode=in}, #{email,jdbctype=varchar,mode=in}, #{address,jdbctype=varchar,mode=in}, #{phone,jdbctype=varchar,mode=in}, #{rc,jdbctype=varchar,mode=out}, #{msg,jdbctype=varchar,mode=out}, #{userid,jdbctype=varchar,mode=out} ) }
service 层java代码。
    大家一定在奇怪这句代码  usermapper.adduser_sp(params); 这前面并没有用变量接收方法的返回值,其实这个方法是没有返回值的,即使你定义了要返回某个值(如map),你会发现无论你得到的永远是null。所以这里根本就不需要接收返回值。那么调用存储过程返回的out参数到要如何接收呢?细心的你可能已经发现了,没错,就是在入参param中!!调用存储过程成功后,你会发现,存储返回的rc、 msg和userid 三个out参数都被放到了你传入的参数params中————也就是说params会在调用存储成功后多出三个字段值rc、msg、userid。
public map adduser_sp(user user) { try { map params=ajaxutil.getmap(); params.put(name, user.getname()); params.put(address, user.getaddress()); params.put(age, user.getage()); params.put(email, user.getemail()); params.put(phone, user.getphone()); usermapper.adduser_sp(params); map map=new hashmap(); map.put(rc, params.get(rc)); map.put(msg, params.get(msg)); map.put(userid, params.get(userid)); return map; } catch (exception e) { logger.error(e); throw new runtimeexception(e); } }
再看下mapper接口方法的定义(没什么好说的就一个接口方法定义)
public void adduser_sp(map params);
最后再看下存储过程代码:
delimiter $$use `easyuidemo`$$drop procedure if exists `adduser_sp`$$create definer=`root`@`localhost` procedure `adduser_sp`( in in_name varchar (50), in in_age integer, in in_email varchar (50), in in_address varchar (200), in in_phone varchar (20), out rc integer, out msg varchar (50), out userid varchar (50))begin declare v_userid varchar (50) default round(rand() * 9000000+10000000) ; declare v_ucount integer default 0 ; select count(*) into v_ucount from t_user where t_user.`id` = v_userid ; if v_ucount > 0 then set rc = - 1 ; set msg = '生成userid重复,插入失败' ; set userid='-00000000'; else insert into t_user (id, `name`, age, email, address, phone) values ( v_userid, in_name, in_age, in_email, in_address, in_phone ) ; set userid = v_userid ; set rc=1; set msg='添加成功'; #commit ; end if ;end$$delimiter ;
存储过程本身也没什么好说的,唯一值得大家关注的是:mysql存储过程中最后有commit和没有commit 是有所不同的。
如果存储过程中没有执行commit,那么spring容器一旦发生了事务回滚,存储过程执行的操作也会回滚。如果存储过程执行了commit,那么数据库自身的事务此时已提交,这时即使在spring容器中托管了事务,并且由于其他原因导致service代码中产生异常而自动回滚,但此存储过程是不会回滚,因为数据自身的事务已在存储过程执行完毕前提交了,  也就是说此时spring回滚对存储过程的操作是无效的了。
其它类似信息

推荐信息