mybatics 中调用mysql存储过程。

说起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类型。

	<select id="queryUserListByLikeName_SP" parameterType="map" resultType="User" statementType="CALLABLE" >
	     {call queryUserList_nameSP(
            #{name,jdbcType=VARCHAR,mode=IN}
          )
         }
	</select>

service 层java代码,调用mapper接口 入参传一个map,返回值是List<User> 类型

	public Map<String, Object> getUserListNameLike(String name) {
       try {
    	     Map<String,Object>  params=AjaxUtil.getMap();
    	     params.put("name", name);
    	     List<User> userList =  userMapper.queryUserListByLikeName_SP(params);
    	     if(userList!=null){
    	    	 Map<String,Object> 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<User> queryUserListByLikeName_SP( Map<String, Object> 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来传字段属性岂不是更合乎情理吗? 这个稍候再跟大家解释下。。。

<select id="addUser_SP" parameterType="map" statementType="CALLABLE" useCache="false">
	 {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}
          )
         }
	</select>

service 层java代码。

大家一定在奇怪这句代码  userMapper.addUser_SP(params); 这前面并没有用变量接收方法的返回值,其实这个方法是没有返回值的,即使你定义了要返回某个值(如Map<String,Object>),你会发现无论你得到的永远是null。所以这里根本就不需要接收返回值。那么调用存储过程返回的out参数到要如何接收呢?细心的你可能已经发现了,没错,就是在入参param中!!调用存储过程成功后,你会发现,存储返回的rc、 msg和userId 三个out参数都被放到了你传入的参数params中————也就是说params会在调用存储成功后多出三个字段值rc、msg、userId。

	public Map<String, Object> addUser_SP(User user) {
		try {
			Map<String,Object>  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<String, Object> map=new HashMap<String,Object>();
		   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<String, Object> 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回滚对存储过程的操作是无效的了。

时间: 2024-10-03 22:48:54

mybatics 中调用mysql存储过程。的相关文章

JAVA调用mysql存储过程noAccessToProcedureBodies错误

问题:在JAVA中调用MYSQL存储过程遇到以下报错: java.sql.SQLException: User does not have access to metadata required to determine stored procedure parameter types. If rights can not be granted, configure connection with "noAccessToProcedureBodies=true" to have dri

PHP多次调用Mysql存储过程报错解决办法

PHP多次调用Mysql数据库的存储过程会出现问题,主要问题为存储过程中执行多次SQL语句不能一一释放导致的,网上找了一些解决办法,比如使用 multi_query 然后一个一个释放,但是发现根本不适合我们的项目,我们使用CI框架写的,更多的是使用CI的数据库处理方法.所以只能另辟蹊径. 一次偶然,把Mysql链接方式改成了mysqli,两种不同的PHP连接mysql的扩展,官方在高版本中推荐使用mysqli,结果却奇迹般好了,使用Mysql长连接也行,天意么? PHP多次调用Mysql存储过程

PHP调用MYSQL存储过程实例

PHP调用MYSQL存储过程实例 标签: mysql存储phpsqlquerycmd 2010-09-26 11:10 11552人阅读 评论(3) 收藏 举报 实例一:无参的存储过程$conn = mysql_connect('localhost','root','root') or die ("数据连接错误!!!");mysql_select_db('test',$conn);$sql = "create procedure myproce()beginINSERT IN

Golang 用go-sql-driver 调用MySQL存储过程时的问题排查

今天在用go-sql-driver做MySQL driver调用MySQL的存储过程时遇到一个罕见的报错.本文对这个错误及其解做一个简单的总结. 1 问题描述 按照go中sql包提供的接口,应用层代码调用MySQL存储过程的代码一般如下所示: result, err := dbh.Exec("call some_procedure(?, ?)", param1, param2) if err != nil { // error handler } // using result...

在java中调用Oracle存储过程

在java中调用Oracle存储过程 本文介绍如何通过java来调用Oracle的存储过程 1. 编写存储过程 CREATE OR REPLACE PROCEDURE sp_pro3(sp_name VARCHAR2,sp_sal NUMBER ) IS BEGIN --根据用户名修改工资 UPDATE emp SET sal=sp_sal WHERE ename=sp_name; END; 引入jdbc6.jar,编写测试类Test.java package testOraclePro; im

mybatis调用mysql存储过程返回多结果集(完整)

最近,有个开发提了个需求,希望中间件支持调用mysql存储过程时支持多结果集返回,因为某些原因我们使用了不少的存储过程,很多复杂的逻辑目前来看交互非常的多,所以从当前的现状来说,这个需求还是蛮合理的.中午抽空特地搜了下,整合完整示例如下: 1.创建测试存储过程 delimiter $$ CREATE PROCEDURE sp_multi_resultset(IN p_operator_company_no int, IN p_operator_no int, OUT p_error_code v

mybatis调用mysql存储过程返回结果集

存储过程中经常需要返回结果集. Mysql 中直接用 select 即可返回结果集.而 oracle 则需要使用游标来返回结果集.这一点 Mysql 相对比较方便,如下代码即可实现输出结果集: 存储过程定义: DELIMITER $$ DROP procedure IF EXISTS pro_sql_data1 $$ CREATE procedure pro_sql_data1(in sear_name varchar(2000)) BEGIN if sear_name is not null

Java调用MySQL存储过程

Java调用MySQL的存储过程,需要用JDBC连接,环境eclipse 首先查看MySQL中的数据库的存储过程,接着编写代码调用 mysql> show procedure status; +------+-------------+-----------+----------------+---------------------+---------------------+---------------+---------+----------------------+----------

php调用mysql存储过程

MYSQL存储过程 原文链接:http://blog.sina.com.cn/s/blog_52d20fbf0100ofd5.html 一.存储过程简介(mysql5.0以上支持) 我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它. 一个存储过程是一个可编程的函数,它在数据库中创建并保存.它可以