反范式设计,冗余用户姓名,修改用户姓名后,业务表同步更新 — 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); }  @Autowired private UserMapper userMapper; //service 层  如果姓名有变化,才更新 if (entity != null && !entity.getRealName().equals(param.getRealName())) {      userMapper.callUpdateUserInfo(userInfo.getId(), userInfo.getRealName()); } 

在 MyBatis-Plus 中调用存储过程(如 CALL UpdateUserInfo('张三', 'zs');),可以通过以下步骤实现:


1. 使用 @Select 注解调用存储过程

如果你的存储过程没有返回值,可以直接使用 @Select 注解调用存储过程。

示例代码

import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository;  @Repository public 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;  @Service public class UserService {      @Autowired     private UserMapper userMapper;      public void updateUserInfo(String newName, String userId) {         userMapper.callUpdateUserInfo(newName, userId);     } } 

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;  @Repository public interface UserMapper {      @Select("CALL UpdateUserInfo(#{newName}, #{userId})")     @Options(statementType = StatementType.CALLABLE)     void callUpdateUserInfo(@Param("newName") String newName, @Param("userId") String userId); } 

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;  @Repository public interface UserMapper {     void callUpdateUserInfo(@Param("newName") String newName, @Param("userId") String userId); } 

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;  @Repository public 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;  @Service public 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"));     } } 

5. 注意事项

  1. 数据库权限

    • 确保应用程序连接数据库的用户有权限调用存储过程。
  2. 存储过程参数

    • 确保传入的参数类型和数量与存储过程定义一致。
  3. 事务管理

    • 如果存储过程中包含多个 SQL 操作,建议在调用存储过程时启用事务管理。
  4. 错误处理

    • 捕获并处理存储过程执行过程中可能抛出的异常。

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;  @Repository public 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;  @Service public 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;  @Component public class AppRunner implements CommandLineRunner {      @Autowired     private UserService userService;      @Override     public void run(String... args) throws Exception {         userService.updateUserInfo("张三", "zs");         System.out.println("存储过程调用完成!");     } } 

发表评论

评论已关闭。

相关文章

当前内容话题