Mybatis使用存儲過程以及原理

一直在用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。數據庫設計

該句執行前:

該句執行後:

到此爲止,知道其內部的設置結果。其實對於使用來講這並無什麼意義,可是多看源碼對本身的思路以及底層仍是有好處,反正我是信了。

純手打,歡迎拍磚~

轉載請指明出處:http://my.oschina.net/u/1991646/blog/731250

相關文章
相關標籤/搜索