反范式设计,冗余用户姓名,修改用户姓名后,业务表同步更新 -- MySQL 存储过程
反范式设计,冗余用户姓名,通过存储过程进行业务表的同步更新。所有的表,在创建的时候,都加了创建人、修改人的字段。。用户姓名发生变化时,要将所有的表都更新一遍。
创建存储过程
MySQL
CREATE PROCEDURE UpdateAllUserInfo(IN userId VARCHAR(255), IN newName VARCHAR(255))BEGIN DECLARE var_table_name VARCHAR(255); DECLARE done INT DEFAULT 0; -- 定义游标,查找所有符合条件的表 DECLARE cur CURSOR FOR -- 变量名要和字段名不同,否则后面取变量时,取不取值 SELECT TABLE_NAME as var_table_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'vipsoft'-- 注意库名 AND COLUMN_NAME IN ('create_user_name','create_userId') GROUP BY TABLE_NAME HAVING COUNT(DISTINCT COLUMN_NAME) = 2; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; -- 打开游标 OPEN cur; -- 循环处理每张表 read_loop: LOOP FETCH cur INTO var_table_name; IF done THEN LEAVE read_loop; END IF; -- 动态生成 SQL 语句 SET @createUser = CONCAT('UPDATE ', var_table_name, ' SET create_user_name = "', newName, '" WHERE create_userId = "', userId, '";'); -- 打印SQL -- SELECT @createUser; -- 执行动态 SQL PREPARE c_stmt FROM @createUser; EXECUTE c_stmt; DEALLOCATE PREPARE c_stmt; -- 动态生成 SQL 语句 SET @updateUser = CONCAT('UPDATE ', var_table_name, ' SET update_user_name = "', newName, '" WHERE update_userId = "', userId, '";'); -- SELECT @updateUser; -- 执行动态 SQL PREPARE u_stmt FROM @updateUser; EXECUTE u_stmt; DEALLOCATE PREPARE u_stmt; END LOOP; -- 关闭游标 CLOSE cur; -- 更新固定表 SET @proInfo = CONCAT('UPDATE project_info SET project_manager_name = "', newName, '" WHERE project_manager_id = "', userId, '";'); -- 执行动态 SQL PREPARE pro_stmt FROM @proInfo; EXECUTE pro_stmt; DEALLOCATE PREPARE pro_stmt; -- 普通SQL更新 UPDATE project_task SET user_name = proName WHERE project_id = proId; END代码调用
MyBatis-Plus 调用代码
/** * 数据层 */public interface SysUserMapper extends BaseMapper<SysUser> { @Select("CALL UpdateAllUserInfo(#{userId}, #{newName})") void callUpdateUserInfo(@Param("userId") String userId, @Param("newName") String newName);}@Autowiredprivate UserMapper userMapper;//service 层如果姓名有变化,才更新if (entity != null && !entity.getRealName().equals(param.getRealName())) { userMapper.callUpdateUserInfo(userInfo.getId(), userInfo.getRealName());}在 MyBatis-Plus 中调用存储过程(如 CALL UpdateUserInfo('张三', 'zs');),可以通过以下步骤实现:
<hr>1. 使用 @Select 注解调用存储过程
如果你的存储过程没有返回值,可以直接使用 @Select 注解调用存储过程。
示例代码
import org.apache.ibatis.annotations.Select;import org.springframework.stereotype.Repository;@Repositorypublic interface UserMapper { @Select("CALL UpdateUserInfo(#{newName}, #{userId})") void callUpdateUserInfo(@Param("newName") String newName, @Param("userId") String userId);}调用方法
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserService { @Autowired private UserMapper userMapper; public void updateUserInfo(String newName, String userId) { userMapper.callUpdateUserInfo(newName, userId); }}<hr>2. 使用 @Options 注解设置存储过程调用
如果存储过程有输出参数或需要设置其他选项,可以使用 @Options 注解。
示例代码
import org.apache.ibatis.annotations.Options;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.mapping.StatementType;import org.springframework.stereotype.Repository;@Repositorypublic interface UserMapper { @Select("CALL UpdateUserInfo(#{newName}, #{userId})") @Options(statementType = StatementType.CALLABLE) void callUpdateUserInfo(@Param("newName") String newName, @Param("userId") String userId);}<hr>3. 使用 XML 配置调用存储过程
如果你更喜欢使用 XML 配置,可以在 Mapper.xml 文件中定义存储过程调用。
示例代码
在 UserMapper.xml 中:
<select id="callUpdateUserInfo" statementType="CALLABLE"> CALL UpdateUserInfo(#{newName}, #{userId})</select>在 UserMapper 接口中:
import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Repository;@Repositorypublic interface UserMapper { void callUpdateUserInfo(@Param("newName") String newName, @Param("userId") String userId);}<hr>4. 处理存储过程的输出参数
如果存储过程有输出参数,可以通过 Map 或自定义对象接收。
示例代码
import org.apache.ibatis.annotations.Options;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.mapping.StatementType;import org.springframework.stereotype.Repository;import java.util.Map;@Repositorypublic interface UserMapper { @Select("CALL UpdateUserInfo(#{newName}, #{userId}, #{result, mode=OUT, jdbcType=INTEGER})") @Options(statementType = StatementType.CALLABLE) void callUpdateUserInfo( @Param("newName") String newName, @Param("userId") String userId, @Param("result") Map<String, Object> resultMap );}调用方法
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.HashMap;import java.util.Map;@Servicepublic class UserService { @Autowired private UserMapper userMapper; public void updateUserInfo(String newName, String userId) { Map<String, Object> resultMap = new HashMap<>(); userMapper.callUpdateUserInfo(newName, userId, resultMap); System.out.println("存储过程执行结果: " + resultMap.get("result")); }}<hr>5. 注意事项
[*]数据库权限:
[*]确保应用程序连接数据库的用户有权限调用存储过程。
[*]存储过程参数:
[*]确保传入的参数类型和数量与存储过程定义一致。
[*]事务管理:
[*]如果存储过程中包含多个 SQL 操作,建议在调用存储过程时启用事务管理。
[*]错误处理:
[*]捕获并处理存储过程执行过程中可能抛出的异常。
<hr>6. 完整示例
以下是一个完整的示例,展示如何在 MyBatis-Plus 中调用存储过程:
存储过程定义
CREATE PROCEDURE UpdateUserInfo(IN new_name VARCHAR(255), IN user_id VARCHAR(255))BEGIN -- 更新逻辑 UPDATE pe_test.user_table SET create_user_name = new_name WHERE create_user_id = user_id; UPDATE pe_test.demo SET member_name = new_name WHERE member_id = user_id;END;MyBatis-Plus 调用代码
import org.apache.ibatis.annotations.Select;import org.springframework.stereotype.Repository;@Repositorypublic interface UserMapper { @Select("CALL UpdateUserInfo(#{newName}, #{userId})") void callUpdateUserInfo(@Param("newName") String newName, @Param("userId") String userId);}import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserService { @Autowired private UserMapper userMapper; public void updateUserInfo(String newName, String userId) { userMapper.callUpdateUserInfo(newName, userId); }}import org.springframework.boot.CommandLineRunner;import org.springframework.stereotype.Component;@Componentpublic class AppRunner implements CommandLineRunner { @Autowired private UserService userService; @Override public void run(String... args) throws Exception { userService.updateUserInfo("张三", "zs"); System.out.println("存储过程调用完成!"); }}
页:
[1]