反范式设计,冗余用户姓名,修改用户姓名后,业务表同步更新 -- 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. 注意事项
数据库权限:
- 确保应用程序连接数据库的用户有权限调用存储过程。
存储过程参数:
- 确保传入的参数类型和数量与存储过程定义一致。
事务管理:
- 如果存储过程中包含多个 SQL 操作,建议在调用存储过程时启用事务管理。
错误处理:
- 捕获并处理存储过程执行过程中可能抛出的异常。
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("存储过程调用完成!");
}
}
反范式设计,冗余用户姓名,修改用户姓名后,业务表同步更新 -- MySQL 存储过程的更多相关文章
- Linux学习总结(十二)—— CentOS用户管理:创建用户、修改用户、修改密码、密码有效期、禁用账户、解锁账户、删除用户、查看所有用户信息
文章首发于Linux学习总结(十二)-- CentOS用户管理,请尊重原创保留原文链接. 创建用户 useradd -g webadmin -d /home/zhangsan zhangsan pas ...
- Centos下新建用户及修改用户目录
Centos下新建用户及修改用户目录 Hillgo 关注 2015.09.22 01:32* 字数 154 阅读 3492评论 0喜欢 3 添加及删除用户 添加用户 test: adduser tes ...
- MongoDB增加用户、删除用户、修改用户读写权限及只读权限(注:转载于http://www.2cto.com/database/201203/125025.html)
MongoDB 增加用户 删除用户 修改用户 读写权限 只读权限, MongoDB用户权限分配的操作是针对某个库来说的.--这句话很重要. 1. 进入ljc 数据库: use ...
- Oracle Database XE 11gR2 自带的用户,新建用户,修改用户密码
操作系统:Windows 10 x64 第一节:下载 Oracle Database XE 11gR2 第二节:安装.验证安装 Oracle Database XE 11gR2 第三节:Oracle ...
- linux命令详解之useradd命令使用方法[linux下 添加用户、删除用户、修改用户密码、用户组管理]
http://www.jb51.net/article/45848.htm Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这 ...
- Cassandra 数据模型设计,根据你的查询来制定设计——反范式设计本质:空间换时间
转自:http://www.infoq.com/cn/articles/best-practice-of-cassandra-data-model-design 不要把Cassandra model想 ...
- oracle创建用户,修改用户,删除用户等关于用户的
--直接修改底层表 USER$ 更换用户名 1.windows 平台下运行 cmd 2.sqlplus /nolog 3.SQL> conn SYSTEM/123@ORCL as sysdba ...
- linux 用户管理修改用户信息、密码状态、删除用户、退出登陆、切换用户
修改用户信息usermoduseradd支持的选项usermod都支持passwd有两个选项-l(在密码串前面加了两个叹号),-u,usermod有两个选项:-L 临时锁定用户(Lock)(在密码串前 ...
- ftp 添加用户及修改用户目录
添加用户 : useradd 用户名 -s /sbin/nologin //限定用户test不能telnet,只能ftp; usermod -s /sbin/bash 用户名 //用户恢复正常 ;该账 ...
- MongoDB之【增加用户认证、增加用户、删除用户、修改用户密码、读写权限、只读权限】
说明:增加用户是针对数据库进行操作 1.进入到数据库 use dbname 2.针对当前数据库添加用户 权限是针对当前数据 1.添加并验证用户 > use admin > db.addUs ...
随机推荐
- S2P主数据助力医药企业建立数据化管理平台
随着国家信息化进程的推进,医药软件行业市场规模正在不断扩大,其应用领域也在逐步拓宽,企业面临着多样化的销售渠道和模式选择.然而,要想在这样的多变市场中占据优势地位,单纯依靠经验决策已经不足以应对挑战. ...
- 利用Catalina快速重新指定tomcat的代码路径
思路: 在/tomcat/conf/Catalina/localhost目录下,建立对应的xml文件,来定义. 方法: 比如:想在 Http://localhost/test-api 显示,且代码放在 ...
- Win11右键显示更多选项设置教程
Win11如何设置右键显示更多选项?如果你觉得每次右键菜单,都是需要点击"显示更多选项"十分麻烦,那么可以通过设置,让其直接显示出现.那么应该如何操作呢?下面小编就为大家带来具体的 ...
- Netty内存池泄漏问题
为了提升消息接收和发送性能,Netty针对ByteBuf的申请和释放采用池化技术,通过PooledByteBufAllocator可以创建基于内存池分配的ByteBuf对象,这样就避免了每次消息读写都 ...
- 2024 Nuxt3 年度生态总结
hello,大家好,我是程序员海军.很荣幸能与大家分享我今年的第三篇文章.在过去的一年里,我深入探索了Nuxt3,并在多个项目中实际应用了这一前沿框架,从而对其功能和应用有了全面而深刻的理解.今天,我 ...
- Qt/C++地图标注点的添加删除移动旋转/指定不同图标和动图/拿到单击信号
一.前言说明 标注点在地图开发中是最常见的应用场景之一,比如在地图上需要显示设备的位置,基本上都是添加标注点,指定图片和尺寸已经经纬度坐标位置.这个功能在每种地图内核中都提供的,这个并没有任何难点,在 ...
- 微信后团队分享:微信后台基于Ray的分布式AI计算技术实践
本文由微信后台Astra项目团队分享,原题"Ray在微信AI计算中的大规模实践",下文进行了排版和内容优化. 1.引言 微信存在大量AI计算的应用场景,主要分为三种:流量分发.产品 ...
- 飞书lark机器人 自动化发版
飞书lark机器人 自动化发版 #1 介绍 开发飞书机器人接收消息并调用构建接口, 实现自动化发版 发送指令 -> 机器人接收指令 -> 调用jenkins-job远程构建与部署 jenk ...
- HUAWEI MindStudio安装配置
HUAWEI MindStudio安装配置 官网: 链接 安装流程 获取软件包 软件包 说明 获取链接 MindStudio_{version}_linux.tar.gz MindStudio软件包, ...
- 第三章 dubbo源码解析目录
7.6 服务远程暴露 - 注册服务到zookeeper 为了安全:服务启动的ip全部使用10.10.10.10 远程服务的暴露总体步骤: 将ref封装为invoker 将invoker转换为expor ...