存儲過程在數據庫中比較常見,雖然大多數存儲過程比較複雜,可是使用 MyBatis 調用時,用法都同樣,所以咱們這一節使用一個簡單的存儲過程來了解 MyBatis 中存儲過程的使用方法。java
存儲過程涉及表 sys_user,建表語句以下。sql
DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用戶ID', `user_name` varchar(50) DEFAULT NULL COMMENT '用戶名', `user_password` varchar(50) DEFAULT NULL COMMENT '密碼', `user_email` varchar(50) DEFAULT 'test@mybatis.tk' COMMENT '郵箱', `user_info` text COMMENT '簡介', `head_img` blob COMMENT '頭像', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1035 DEFAULT CHARSET=utf8 COMMENT='用戶表';
準備測試數據以下。數據庫
INSERT INTO `sys_user` VALUES ('1', 'admin', '123456', 'admin@mybatis.tk', '管理員用戶', 0x1231231230, '2016-06-07 01:11:12'); INSERT INTO `sys_user` VALUES ('1001', 'test', '123456', 'test@mybatis.tk', '測試用戶', 0x1231231230, '2016-06-07 00:00:00');
對應實體類SysUser
以下:數組
/** * 用戶表 */ public class SysUser implements Serializable { private static final long serialVersionUID = 1L; /** * 用戶ID */ private Long id; /** * 用戶名 */ private String userName; /** * 密碼 */ private String userPassword; /** * 郵箱 */ private String userEmail; /** * 簡介 */ private String userInfo; /** * 頭像 */ private byte[] headImg; /** * 建立時間 */ private Date createTime; //省略 getter 和 setter }
咱們先建立以下的存儲過程。緩存
# 第一個存儲過程
# 根據用戶 id 查詢用戶其餘信息
# 方法看着很奇葩,可是展現了多個輸出參數
DROP PROCEDURE IF EXISTS `select_user_by_id`; DELIMITER ;; CREATE PROCEDURE `select_user_by_id`( IN userId BIGINT, OUT userName VARCHAR(50), OUT userPassword VARCHAR(50), OUT userEmail VARCHAR(50), OUT userInfo TEXT, OUT headImg BLOB, OUT createTime DATETIME) BEGIN # 根據用戶 id 查詢其餘數據 select user_name,user_password,user_email,user_info,head_img,create_time INTO userName,userPassword,userEmail,userInfo,headImg,createTime from sys_user WHERE id = userId; END ;; DELIMITER ;
<select id="selectUserById" statementType="CALLABLE" useCache="false"> {call select_user_by_id( #{id, mode=IN}, #{userName, mode=OUT, jdbcType=VARCHAR}, #{userPassword, mode=OUT, jdbcType=VARCHAR}, #{userEmail, mode=OUT, jdbcType=VARCHAR}, #{userInfo, mode=OUT, jdbcType=VARCHAR}, #{headImg, mode=OUT, jdbcType=BLOB, javaType=_byte[]}, #{createTime, mode=OUT, jdbcType=TIMESTAMP} )} </select>
在調用存儲過程的方法中,咱們須要把 statementType
設置爲 CALLABLE
,在使用 select
元素中調用存儲過程時,因爲存儲過程方式不支持 MyBatis 的二級緩存(後面章節會介紹),爲了不緩存配置致使出錯,咱們直接將 select
元素的 useCache
屬性設置爲 false
。mybatis
在存儲過程當中使用參數時,除了寫上必要的屬性名外,還必須指定參數的 mode
(模式),可選值爲 IN、OUT、INOUT 三種,入參使用 IN,出參使用 OUT,輸入輸出參數使用 INOUT。從上面代碼能夠輕易看出 IN 和 OUT 的兩種模式的區別,那就是 OUT 模式的參數,必須指定 jdbcType。這是由於在 IN 模式下,MyBatis 提供了默認的 jdbcType
,在 OUT 模式下沒有提供,所以必須指定 jdbcType
,另外在使用 Oracle 數據庫時,若是入參存在 null 的狀況,那麼也必須指定 jdbcType
。app
除了上面提到的這幾點外,headImg
還特別設置了 javaType
。在 MyBatis 映射的 Java 類中咱們都不推薦使用基本類型,可是數據庫 BLOB 類型對應的 Java 類型咱們一般都是寫成 byte[] 字節數組,由於 byte[] 數組不會有默認值的問題,因此不會影響咱們通常的使用。可是在不指定 javaType
的狀況下,MyBatis 默認使用 Byte
類型。因爲咱們使用的 byte
是基本類型,因此設置 javaType
的時候,基本類型要使用帶下劃線方式的類型,在這裏就是 byte[]
,_byte
對應的是基本類型,byte
對應的是 Byte
類型,在使用 javaType
時必定要注意。測試
/** * 使用存儲過程查詢用戶信息 * * @param user * @return */ void selectUserById(SysUser user);
由於咱們這個存儲過程沒有返回值(不要和出參混淆),因此咱們返回值類型使用 void,若是你把返回值設置爲 SysUser
或 List<SysUser>
也不會報錯,可是任什麼時候候返回值都是 null
。spa
@Test public void testSelectUserById(){ SqlSession sqlSession = //獲取SqlSession的方法 try { //這個例子的XML和接口都定義在UserMapper中 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); SysUser user = new SysUser(); user.setId(1L); userMapper.selectUserById(user); Assert.assertNotNull(user.getUserName()); System.out.println("用戶名:" + user.getUserName()); } finally { sqlSession.close(); } }
執行測試,輸出以下日誌:日誌
DEBUG [main] - ==> Preparing: {call select_user_by_id( ?, ?, ?, ?, ?, ?, ? )} DEBUG [main] - ==> Parameters: 1(Long) 用戶名:admin
使用出參方式的時候,一般狀況下咱們會使用對象中的屬性接收出參的值,或者使用 Map
類型方法入參接收返回值。這兩種狀況下有很大的區別。當咱們使用 POJO 對象接收出參時,咱們必須保證全部出參在 POJO 中都有對應的屬性存在,不然就會拋出相似 「Could not set property 'xxx'」
的錯誤,這是因爲 POJO 對象中不存在出參對應的 setter 方法致使的。使用 Map 類型時就不須要必須存在該屬性,當 Map 接收了存儲過程的出參時,能夠經過 Map
對象的 get("屬性名")
方法獲取出參的值。
除了上面提到的錯誤外,當你在執行存儲過程時,還可能會遇到下面的錯誤:
Parameter number x is not an OUT parameter
這個錯誤可能的緣由是由於你調用的存儲過程不存在,或者 MyBatis 中寫的出參和數據庫存儲過程的出參對應不上而致使的。