一直在用Mybatis,身处互联网公司,对于存储过程这块一直没怎么使用,数据库设计基本上都是单表+冗余+服务划分来设计,关键部分使用缓存,所以对存储过程一直不怎么感冒。今天偶然看到一篇Mybatis操做存储过程的文章,发现了一奇妙的事情(多是见识少了些),传入的参数在查询成功后就有告终果的值。二话不说下载源码就开干!java
-------------------------------------------一个文档中的内容,未标明做者,这里就不注明版权了------------------------mysql
首先是,数据库建立的脚本:sql
CREATE TABLE p_user( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), sex CHAR(2) ); INSERT INTO p_user(NAME,sex) VALUES('A',"男"); INSERT INTO p_user(NAME,sex) VALUES('B',"女"); INSERT INTO p_user(NAME,sex) VALUES('C',"男"); #建立存储过程( 查询获得男性或女性的数量, 若是传入的是 0 就女性不然是男性) DELIMITER $ CREATE PROCEDURE tssss.ges_user_count(IN sex_id INT, OUT user_count INT) BEGIN IF sex_id=0 THEN SELECT COUNT(*) FROM tssss.p_user WHERE p_user.sex='女' INTO user_count; ELSE SELECT COUNT(*) FROM tssss.p_user WHERE p_user.sex='男' INTO user_count; END IF; END $ #调用存储过程 DELIMITER ; SET @user_count = 0; CALL tssss.ges_user_count(1, @user_count); SELECT @user_count;
而后新建一个Java项目,须要的jar包为Mybatis的jar和mysql链接jar,以下:数据库
mybatis-3.2.8.jar mysql-connector-java-5.1.34.jar
新建一个Mybatis的配置文件sqlMapConfig.xmlapache
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/tssss?characterEncoding=UTF-8" /> <property name="username" value="root" /> <property name="password" value="" /> </dataSource> </environment> </environments> <mappers> <mapper resource="mybatis2/TssssMapper.xml" /> </mappers> </configuration>
新建一个mapper映射文件TssssMapper.xml:缓存
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="mybatis2.Tssss"> <select id="getCount" resultType="hashmap" statementType="CALLABLE"> {call ges_user_count(#{sex_id,mode=IN,jdbcType=INTEGER},#{result,mode=OUT,jdbcType=INTEGER}) } </select> </mapper>
新建一个测试类:session
package mybatis2; import java.io.IOException; import java.io.Reader; import java.util.HashMap; import java.util.Map; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.ResultContext; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class A { public static void main(String[] args) throws IOException { String resource = "sqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(resource); SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader); SqlSession session = ssf.openSession(); Map<String, Object> paramMap = new HashMap<>(); paramMap.put("sex_id", 1); try { Object returnValue = session.selectOne("getCount", paramMap); System.out.println("result="+paramMap.get("result")); System.out.println("sex_id="+paramMap.get("sex_id")); System.out.println("returnValue="+returnValue); } catch (Exception e) { e.printStackTrace(); } finally { session.close(); } System.out.println("result="+paramMap.get("result")); System.out.println("sex_id="+paramMap.get("sex_id")); } }
--------------------------------------------------------------------------------------------------------------------------------------------------mybatis
很神奇的发现,传入的paraMap参数在查询后有了存储过程的结果值 result,我决定去找找源码。经过跟踪找到了两个关键的类org.apache.ibatis.mapping.ParameterMode.java和org.apache.ibatis.executor.resultset.DefaultResultSetHandler.Java:app
package org.apache.ibatis.mapping; /** * @author Clinton Begin */ public enum ParameterMode { IN, OUT, INOUT }
public void handleOutputParameters(CallableStatement cs) throws SQLException { final Object parameterObject = parameterHandler.getParameterObject(); final MetaObject metaParam = configuration.newMetaObject(parameterObject); final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); for (int i = 0; i < parameterMappings.size(); i++) { final ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) { if (ResultSet.class.equals(parameterMapping.getJavaType())) { handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam); } else { final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler(); metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1)); } } } }
其中在DefaultResultSetHandler类中的handleOutputParameters(CallableStatement cs)方法中处理了传入参数和传出的参数。有兴趣的童鞋也能够试着跟一下,这里判断了当parameterMapping.getMode() == ParameterMode.OUT时候,即如今操做的为存储过程的out参数,所以这里在metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1)); 该句的时候将存储过程的result值设置给了输入的参数map。数据库设计
该句执行前:
该句执行后:
到此为止,知道其内部的设置结果。其实对于使用来讲这并无什么意义,可是多看源码对本身的思路以及底层仍是有好处,反正我是信了。
纯手打,欢迎拍砖~