MyBatis 示例之存储过程
存储过程在数据库中比较常见,虽然大多数存储过程比较复杂,但是使用 MyBatis 调用时,用法都一样,因此我们这一节使用一个简单的存储过程来了解 MyBatis 中存储过程的使用方法。
基本准备
存储过程涉及表 sys_user,建表语句如下。
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 ('', 'admin', '', 'admin@mybatis.tk', '管理员用户', 0x1231231230, '2016-06-07 01:11:12');
INSERT INTO `sys_user` VALUES ('', 'test', '', '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 ;
创建XML方法
<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。
在存储过程中使用参数时,除了写上必要的属性名外,还必须指定参数的 mode(模式),可选值为 IN、OUT、INOUT 三种,入参使用 IN,出参使用 OUT,输入输出参数使用 INOUT。从上面代码可以轻易看出 IN 和 OUT 的两种模式的区别,那就是 OUT 模式的参数,必须指定 jdbcType。这是因为在 IN 模式下,MyBatis 提供了默认的 jdbcType,在 OUT 模式下没有提供,因此必须指定 jdbcType,另外在使用 Oracle 数据库时,如果入参存在 null 的情况,那么也必须指定 jdbcType。
除了上面提到的这几点外,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。
编写测试
@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: (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 中写的出参和数据库存储过程的出参对应不上而导致的。
MyBatis 示例之存储过程的更多相关文章
- Mybatis调用PostgreSQL存储过程实现数组入参传递
注:本文来源于 < Mybatis调用PostgreSQL存储过程实现数组入参传递 > 前言 项目中用到了Mybatis调用PostgreSQL存储过程(自定义函数)相关操作,由于Pos ...
- MyBatis 示例-类型处理器
MyBatis 提供了很多默认类型处理器,参考官网地址:链接,除了官网提供的类型处理器,我们也可以自定义类型处理器. 具体做法为:实现 org.apache.ibatis.type.TypeHandl ...
- MyBatis调用Oracle存储过程
MyBatis调用Oracle存储过程 1.无输入和输出参数的存储过程 2.带有输入和输出参数的存储过程 3.返回游标的存储过程 mybatis中的配置文件代码 <resultMap type= ...
- Mybatis 示例之 复杂(complex)属性(property)
Mybatis示例专栏:http://blog.csdn.net/column/details/mybatis-sample.html Mybatis的复杂属性,Mybatis的这个特点很少被提及,但 ...
- Mybatis 示例之 Association - 偶尔记一下 - 博客频道 - CSDN.NET
body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...
- mybatis 调用 oracle 存储过程 select into 无记录时NO_DATA_FOUND异常处理分析
首先根据这篇文章:http://www.cnblogs.com/coolzdp/p/7717332.html 我们知道存储过程中 SELECT * INTO 如果没有记录是不会往下执行的,直接抛出NO ...
- MyBatis 示例-传递多个参数
映射器的主要元素: 本章介绍 select 元素中传递多个参数的处理方式. 测试类:com.yjw.demo.MulParametersTest 使用 Map 传递参数(不建议使用) 使用 MyBat ...
- MyBatis 示例-简介
简介 为了全面熟悉 MyBatis 的使用,整理一个 MyBatis 的例子,案例中包含了映射器.动态 SQL 的使用.本章先介绍项目结构和配置. 项目地址:链接 数据库表的模型关系:链接 项目结构 ...
- MyBatis 示例-联合查询
简介 MyBatis 提供了两种联合查询的方式,一种是嵌套查询,一种是嵌套结果.先说结论:在项目中不建议使用嵌套查询,会出现性能问题,可以使用嵌套结果. 测试类:com.yjw.demo.JointQ ...
随机推荐
- CPNtools 模拟工具适合分析什么样的协议
最近梳理和CPNtools和Scyther之间的性能和差别.方便后面整理使用 1.库所的托肯值是什么? 托肯值也叫作令牌, 即网络系统中的资源,托肯的数目值代表了网络赋予的资源大小.在一个活的网络系统 ...
- [nginx] nginx源码分析--proxy模式下nginx的自动重定向auto_redirect
描述 我们配置了一个proxy模式下的nginx, upstream backend-test { server ; } server { listen ; location = /nginx/hww ...
- Linux命令——lspci
参考:7 Linux lspci Command Examples to Get PCI Bus Hardware Device Info 简介 lspci可以看成“ls” + “pci”.lspci ...
- Spring Boot SockJS应用例子
1.SockJS用javascript实现的socket连接,兼容各种浏览器的WebSocket支持库2.WebSocket是H5的,不支持H5的浏览器没法使用.3.SockJS它提供类似于webso ...
- # Spring Boot & thymeleaf模板 使用 th:each 遍历对象数组 -生成一批html标签体
在controller中取出emps 对象数组 //1.查询所有的员工,返回列表页面 @GetMapping("/emps") public String list(Model m ...
- springboot 之 使用poi进行数据的导出(一)
使用的是idea+restful风格 第一:引入依赖为: <!--poi--> <dependency> <groupId>org.apache.xmlbeans& ...
- Flask - 请求响应 | session | 闪现 | 请求扩展 | 中间件
请求响应 flask的请求信息都在request里 flask的响应方式有四剑客,也可以自定义响应 请求相关信息 # request.method 提交的方法 # request.args get请求 ...
- S1_搭建分布式OpenStack集群_02 虚拟机环境配置
一.配置主机名及hosts和防火墙(只演示一台,其他机器配置方式一样)vim /etc/hosts 加入 10.10.11.11 controller10.10.11.12 compute11 ...
- RookeyFrame 信息 常用信息整理
博客 https://www.cnblogs.com/rookey/ gitee的地址: https://gitee.com/rookey/Rookey.Frame-v2.0 https://gite ...
- CODE FESTIVAL 2016 qual A题解
传送门 不知道为什么\(AGC\)系列的题里突然多了这些--那就做吧-- \(A\) 什么玩意儿-- upd:因为没看到最后要加换行居然没有\(1A\)好气哦-- const int N=15; ch ...