以下例子展示Mybatis存储过程调用,与普通查询基本一样,只是在配置映射时要加上statementType=“CALLABLE”,由于存储过程方式不支持Mybatis的二级缓存,所以要加上useCache=“false”。
在存储过程中使用参数时,除了配置属性名外,还需要指定mode参数,可选值为IN、OUT、INOUT三种,入参用IN,出参用OUT,OUT模式必须指定jdbcType。另外在oracle数据库时,如果入参存在null的也要指定jdbcType。
使用出参方式时,通常情况下会使用javaBean或Map类型接收。这2种方式有很大区别:
当使用JavaBean对象接收出参时,必须保证所有出参在JavaBean中都有对应的属性。否则会抛出类似“Could not set property ‘XXXX’”的错误。
使用map类型时就不必保证所有出参都有对应的属性,可使用get(“属性名”)取出值。

1. 存储过程select_user_by_id,通过用户id查询用户信息,无返回值并使用javaBean接收出参

  • 在MYSQL中创建存储过程select_user_by_id
# 根据用户编号查询其它数据
DROP PROCEDURE IF EXISTS ‘select_user_by_id’;
DELIMITER ;;
CREATE PROCEDURE `select_user_by_id`(
		IN userId BIGINT, 
        OUT userName VARCHAR(60), 
        OUT userPassword VARCHAR(60), 
        OUT userEmail VARCHAR(60), 
        OUT userInfo TEXT, 
        OUT headImg BLOB, 
        OUT createTime DATETIME)
BEGIN
# 根据用户编号查询其它数据
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 ;
  • 在SysUserMapper.xml中添加存储过程调用方法selectUserByIdPro
<!-- 存储过程的select_user_by_id调用 ,使用javaBean接收出参-->
  <select id="selectUserByIdPro" 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>
  • 在SysUserMapper接口中添加存储过程调用方法selectUserByIdPro
/**
     * 使用存储过程,根据用户id查用户信息,使用javaBean(SysUser)接收存储过程出参
     * 因为这个存储过程没有返回值(不要与出参搞混),所以返回值类型为void,当然设为
     * SysUser或List<SysUser>都不会报错,不过永远返回null
     * @param user
     */
    void selectUserByIdPro(SysUser user);
  • 在UserMaperTest添加selectUserByIdPro测试方法
@Test
	public void testSelectUserByIdPro() {
		// 获取SqlSession
		SqlSession sqlSession = openSession();
		try {
			// 获取SysUserMapper接口
			SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
			
			// 查询条件
			SysUser user = new SysUser();
			user.setId(1L);
			
			// 调用selectUserByIdPro方法
			userMapper.selectUserByIdPro(user);
			
			// user不为空
			Assert.assertNotNull(user.getUserName());
			
			// 查询用户信息
			System.out.println(user);
		} finally {
			sqlSession.close();
		}
	}
  • select_user_by_id 运行结果(可以看到存储过程已调用并用户信息已查出来)
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro] - ==>  Preparing: {call select_user_by_id ( ?, ?, ?, ?, ?, ?, ? )} 
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro] - ==> Parameters: 1(Long)
SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@mybatis.ex, createTime=2018-10-01 18:27:36.0, userInfo=管理员, headImg=null]

2. 上一存储过程select_user_by_id有返回值的写法

  • 在MYSQL中创建存储过程select_user_by_id_1
CREATE PROCEDURE `select_user_by_id_1`(IN userId BIGINT)
BEGIN
# 根据用户编号查询其它数据
SELECT * FROM sys_user WHERE id = userId;
END;
  • 在SysUserMapper.xml中添加存储过程调用方法selectUserByIdPro1
<!-- 存储过程的调用 ,有返回值的用法,返回值使用resultMap指定 -->
  <select id="selectUserByIdPro1" statementType="CALLABLE" useCache="false" resultMap="userMap">
  	{call select_user_by_id_1 (#{id, mode=IN})}
  </select>
  • 在SysUserMapper接口中添加存储过程调用方法selectUserByIdPro1
/**
     * 使用存储过程,根据编号查用户信息
     * @param id
     */
    SysUser selectUserByIdPro1(Long id);
  • 在UserMaperTest添加selectUserByIdPro1测试方法
@Test
	public void testSelectUserByIdPro1() {
		// 获取SqlSession
		SqlSession sqlSession = openSession();
		try {
			// 获取SysUserMapper接口
			SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
			
			// 调用selectUserByIdPro1方法
			SysUser user = userMapper.selectUserByIdPro1(1L);
			
			// user不为空
			Assert.assertNotNull(user.getUserName());
			
			// 查询用户信息
			System.out.println(user);
		} finally {
			sqlSession.close();
		}
	}
  • select_user_by_id_1 运行结果(可以看到存储过程已调用并用户信息已查出来)
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro1] - ==>  Preparing: {call select_user_by_id_1 (?)} 
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro1] - ==> Parameters: 1(Long)
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro1] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro1] - <==        Row: 1, admin, 123456, admin@mybatis.ex, <<BLOB>>, <<BLOB>>, 2018-10-01 18:27:36.0
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro1] - <==      Total: 1
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserByIdPro1] - <==    Updates: 0
SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@mybatis.ex, createTime=Mon Oct 01 18:27:36 CST 2018, userInfo=管理员, headImg=null]

3. 存储过程select_user_page,根据用户名和分页参数进行查询,返回总数和分页数据,使用Map接收出参。有返回值

  • 在MYSQL中创建存储过程select_user_page
CREATE PROCEDURE `select_user_page`(
		IN userName VARCHAR(60),
        IN _offset BIGINT,
		IN _limit BIGINT,
        OUT total BIGINT)
BEGIN
# 查询总数
SELECT COUNT(*) INTO total FROM sys_user
where user_name LIKE CONCAT('%',userName,'%');

# 分页查询数据
SELECT * FROM sys_user where user_name LIKE CONCAT('%',userName,'%') LIMIT _offset, _limit;
END;
  • 在SysUserMapper.xml中添加存储过程调用方法selectUserPage
<!-- 存储过程的调用,返回值使用resultMap指定,使用map接收出参-->
  <select id="selectUserPage" statementType="CALLABLE" useCache="false" resultMap="userMap">
  	{call select_user_page (
  		#{userName, mode=IN},
  		#{offset, mode=IN},
  		#{limit, mode=IN},
  		#{total, mode=OUT, jdbcType=BIGINT}
  	)}
  </select>
  • 在SysUserMapper接口中添加存储过程调用方法selectUserPage
/**
     * 使用存储过程分页查询,根据编号查用户信息
     * @param params
     */
    List<SysUser> selectUserPage(Map<String, Object> params);
  • 在UserMaperTest添加selectUserPage测试方法
@Test
	public void testSelectUserPage() {
		// 获取SqlSession
		SqlSession sqlSession = openSession();
		try {
			// 获取SysUserMapper接口
			SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
			
			// 查询条件
			Map<String, Object> params = new HashMap<>();
			params.put("userName", "test");
			params.put("offset", 0);
			params.put("limit", 10);
			
			// 调用selectUserPage方法
			List<SysUser> users = userMapper.selectUserPage(params);
			
			// user不为空
			Assert.assertNotNull(params.get("total"));
			
			// 查询用户信息
			System.out.println(params);
			
			System.out.println(users);
		} finally {
			sqlSession.close();
		}
	}
  • select_user_page运行结果
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserPage] - ==>  Preparing: {call select_user_page ( ?, ?, ?, ? )} 
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserPage] - ==> Parameters: test(String), 0(Integer), 10(Integer)
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserPage] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserPage] - <==        Row: 1001, test, 123456, test@mybatis.ex, <<BLOB>>, <<BLOB>>, 2018-10-02 17:17:11.0
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserPage] - <==      Total: 1
[ex.mybatis.rbac.mapper.SysUserMapper.selectUserPage] - <==    Updates: 0
{total=1, offset=0, limit=10, userName=test}
[SysUser [id=1001, userName=test, userPassword=123456, userEmail=test@mybatis.ex, createTime=Tue Oct 02 17:17:11 CST 2018, userInfo=测试用户, headImg=null]]

4. 存储过程insert_user_and_roles,保存用户信息和角色关联信息

  • 在MYSQL中创建存储过程insert_user_and_roles
CREATE PROCEDURE `insert_user_and_roles`(
		OUT userId BIGINT,
        OUT createTime DATETIME,
        IN userName VARCHAR(60), 
        IN userPassword VARCHAR(60), 
        IN userEmail VARCHAR(60), 
        IN userInfo TEXT, 
        IN headImg BLOB,
		IN roleIds VARCHAR(200))
BEGIN
# 设置创建时间
SET createTime = NOW();

# 插入数据
INSERT INTO sys_user (user_name, user_password, user_email, user_info, head_img, create_time) 
VALUES (userName, userPassword, userEmail, userInfo, headImg, createTime);

# 获取自增主键
SELECT LAST_INSERT_ID() INTO userId;

# 保存用户和角色关系信息
SET roleIds = CONCAT(',',roleIds,',');
INSERT INTO sys_user_role (user_id, role_id) 
SELECT userId, id from sys_role where INSTR(roleIds,CONCAT(',',id,',')) > 0;

END;
  • 在SysUserMapper.xml中添加存储过程调用方法insertUserAndRoles
<!-- 存储过程的调用 ,保存用户信息和角色关联信息-->
  <insert id="insertUserAndRoles" statementType="CALLABLE">
  	{call insert_user_and_roles (
  		#{user.id, mode=OUT, jdbcType=BIGINT},
  		#{user.createTime, mode=OUT, jdbcType=TIMESTAMP},
  		#{user.userName, mode=IN},
  		#{user.userPassword, mode=IN},
  		#{user.userEmail, mode=IN},
  		#{user.userInfo, mode=IN},
  		#{user.headImg, mode=IN, jdbcType=BLOB},
  		#{roleIds, mode=IN}
  	)}
  </insert>
  • 在SysUserMapper接口中添加存储过程调用方法insertUserAndRoles
/**
     * 使用存储过程插入数据,并获取主键
     * @param user
     * @param roleIds
     * @return
     */
    int insertUserAndRoles(@Param("user") SysUser user, @Param("roleIds") String roleIds);
  • 在UserMaperTest添加insertUserAndRoles测试方法
@Test
	public void testInsertUserAndRoles() {
		// 获取SqlSession
		SqlSession sqlSession = openSession();
		try {
			// 获取SysUserMapper接口
			SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
			
			// 用户信息
			SysUser user = new SysUser();
			user.setUserName("test3");
			user.setUserPassword("myccl210");
			user.setUserEmail("test3@mybatis.ex");
			user.setUserInfo("测试存储过程插入方法");
			user.setHeadImg(new byte[]{1,2,3});
			user.setCreateTime(new Date());
			
			// 调用insertUserAndRoles方法
			int row = userMapper.insertUserAndRoles(user, "1,2");
			
			// row 不为空
			Assert.assertNotNull(row);
		} finally {
			sqlSession.commit();
			sqlSession.close();
		}
	}
  • insert_user_and_roles 运行结果
[ex.mybatis.rbac.mapper.SysUserMapper.insertUserAndRoles] - ==>  Preparing: {call insert_user_and_roles ( ?, ?, ?, ?, ?, ?, ?, ? )} 
[ex.mybatis.rbac.mapper.SysUserMapper.insertUserAndRoles] - ==> Parameters: test3(String), myccl210(String), test3@mybatis.ex(String), 测试存储过程插入方法(String), java.io.ByteArrayInputStream@6cc7b4de(ByteArrayInputStream), 1,2(String)
[ex.mybatis.rbac.mapper.SysUserMapper.insertUserAndRoles] - <==    Updates: 2
  • insert_user_and_roles 运行结果,数据库结果 用户信息:

mybatis postgresql调用带游标的存储过程 mybatis调用存储过程传参_存储过程

  • 用户角色信息:

mybatis postgresql调用带游标的存储过程 mybatis调用存储过程传参_用户信息_02

5. 存储过程delete_user_by_id,删除用户信息和角色关联信息

  • 在MYSQL中创建存储过程delete_user_by_id
CREATE PROCEDURE `delete_user_by_id`(IN userId BIGINT)
BEGIN
DELETE FROM sys_user_role WHERE user_id = userId;
DELETE FROM sys_user where id = userId;
END;
  • 在SysUserMapper.xml中添加存储过程调用方法deleteUserById
<!-- 存储过程的调用 ,删除用户信息和角色关联信息 -->
  <delete id="deleteUserById" statementType="CALLABLE">
  	{call delete_user_by_id (#{id, mode=IN})}
  </delete>
  • 在SysUserMapper接口中添加存储过程调用方法deleteUserById
/**
     * 使用存储过程删除数据
     * @param id
     * @return
     */
    int deleteUserById(Long id);
  • 在UserMaperTest添加deleteUserById测试方法
@Test
	public void testDeleteUserById() {
		// 获取SqlSession
		SqlSession sqlSession = openSession();
		try {
			// 获取SysUserMapper接口
			SysUserMapper userMapper = sqlSession.getMapper(SysUserMapper.class);
			
			// 调用deleteUserById方法
			int row = userMapper.deleteUserById(1034L);
			
			System.out.println(row);
		} finally {
			sqlSession.commit();
			sqlSession.close();
		}
	}
  • delete_user_by_id运行结果(查数据库发现刚才插入的1034数据给删除了)
[ex.mybatis.rbac.mapper.SysUserMapper.deleteUserById] - ==>  Preparing: {call delete_user_by_id (?)} 
[ex.mybatis.rbac.mapper.SysUserMapper.deleteUserById] - ==> Parameters: 1034(Long)
[ex.mybatis.rbac.mapper.SysUserMapper.deleteUserById] - <==    Updates: 1