MyBatis学习:存储过程
一、存储过程1CREATE 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)
一、存储过程1
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
在UserMapper.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, OUT 模式的参数必须指定jdbcType。 这是因为在IN 模式下, MyBatis 提供了默认的jdbcType,在OUT 模式下没有提供。
在UserMapper.xml映射文件对应的接口文件中添加方法:
/**
* 使用存储过程查询用户信息
* @param user
*/
void selectUserById (SysUser user);
因为这个存储过程没有返回值(不要和出参混淆),所以返回值类型使用void。 把返回值设置为SysUser 或List 也不会报错,但是任何时候返回值都是null。我们使用出参的方式得到用户的信息。
测试代码:
@Test
public void SelectUserByid(){
//获取SqlSession
SqlSession sqlSession = getSqlSession();
try{
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user = new SysUser();
user.setId(1L);
userMapper.selectUserById(user);
System.out.println("用户名:"+user.getUserName());
}finally {
sqlSession.close();
}
}
使用出参方式时,通常情况下会使用对象中的属性接收出参的值,或者使用Map 类型接收返回值。这两种情况有很大的区别。当使用 JavaBean 对象接收出参时,必须保证所有出参在JavaBean 中都有对应的属性存在,否则就会抛出类似“Could not set property ’ xxx ’ 这样的错误。这是由于JavaBean 对象中不存在出参对应的setter 方法,使用Map 类型时就不需要保证所有出参都有对应的属性,当Map 接收了存储过程的出参时,可以通过Map 对象的get ( ”属性名”) 方法获取出参的值。
二、存储过程2
CREATE PROCEDURE `select_user_page`(
IN userName VARCHAR(50),
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
在UserMapper.xml映射文件中添加如下代码:
<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>
该方法和上例方法的区别在于, select 标签设置了resultMap,因为该方法通过total 出参得到了查询的总数,通过存储过程返回了最后的结果集,所以需要设置返回值信息。
在对应接口文件添加方法:
/**
* 使用存储过程分页查询
* @param params
* @return
*/
List<SysUser> selectUserPage(Map<String,Object> params) ;
由于需要多个入参和一个出参,而入参中除了userName 属性在SysUser 中,其他3 个参数都和SysUser 无关,除了为了使用SysUser 而增加3 个属性之外,这里我们为了实现方法多样化,也为了印证上一个方法中使用 Map 接收返回值的用法是正确的, 因此使用 Map类型作为参数。
测试代码:
@Test
public void selectUserPage(){
//获取SqlSession
SqlSession sqlSession = getSqlSession();
try{
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> params = new HashMap<>();
params.put("userName","ad");
params.put("offset",0);
params.put("limit",10);
List<SysUser> userList = userMapper.selectUserPage(params);
Long totle = (Long)params.get("total");
System.out.println("总数:"+totle);
}finally {
sqlSession.close();
}
}
测试代码的 Map 参数中不存在 total,执行了存储过程方法后,通过 get 方法得到了total 的值。
三、存储过程3,4
-- 保存用户信息和角色关联信息
CREATE PROCEDURE `insert_user_and_roles`(
OUT userId BIGINT,
IN userName VARCHAR(50),
IN userPassword VARCHAR(50),
IN userEmail VARCHAR(50),
IN userInfo TEXT,
IN headImg BLOB,
OUT createTime DATETIME,
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
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
在UserMapper.xml文件中添加如下代码:
<insert id="insertUserAndRoles" statementType="CALLABLE">
{call insert_user_and_roles(
#{user.id, mode=OUT, jdbcType=BIGINT},
#{user.userName, mode=IN},
#{user.userPassword, mode=IN},
#{user.userEmail, mode=IN},
#{user.userInfo, mode=IN},
#{user.headImg, mode=IN, jdbcType=BLOB},
#{user.createTime, mode=OUT, jdbcType=TIMESTAMP},
#{roleIds, mode=IN}
)}
</insert>
<delete id="deleteUserById" statementType="CALLABLE">
{call delete_user_by_id(#{id, mode=IN})}
</delete>
在对应接口文件添加如下方法:
/**
* 保存用户信息和角色关联信息
*
* @param user
* @param roleIds
* @return
*/
int insertUserAndRoles(@Param("user")SysUser user, @Param("roleIds")String roleIds);
/**
* 根据用户 id 删除用户和用户的角色信息
*
* @param id
* @return
*/
int deleteUserById(Long id);
测试代码:
@Test
public void testInsertAndDelete(){
//获取 sqlSession
SqlSession sqlSession = getSqlSession();
try {
//获取 UserMapper 接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser user = new SysUser();
user.setUserName("test1");
user.setUserPassword("123456");
user.setUserEmail("test@mybatis.tk");
user.setUserInfo("test info");
//正常情况下应该读入一张图片存到 byte 数组中
user.setHeadImg(new byte[]{1,2,3});
//插入数据
userMapper.insertUserAndRoles(user, "1,2");
Assert.assertNotNull(user.getId());
Assert.assertNotNull(user.getCreateTime());
//可以执行下面的 commit 后查看数据库中的数据
//sqlSession.commit();
//测试删除刚刚插入的数据
userMapper.deleteUserById(user.getId());
} finally {
//不要忘记关闭 sqlSession
sqlSession.commit();
sqlSession.close();
}
}
更多推荐
所有评论(0)