1. 程式人生 > >【筆記】Mybatis高階查詢(七)--儲存過程呼叫

【筆記】Mybatis高階查詢(七)--儲存過程呼叫

以下例子展示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, [email protected], 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, [email protected], <<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, [email protected], 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, [email protected], <<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, [email protected], 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("[email protected]");
			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), [email protected](String), 測試儲存過程插入方法(String), [email protected](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