以下例子展示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 运行结果,数据库结果 用户信息:
- 用户角色信息:
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