mysql数据库复制数据表时的风险
最近在使用redis的缓存技术时,在项目中需要在插入mysql数据表记录的同时,缓存数据到redis。在创建数据表时,为了方便,直接使用复制另外一个数据库中的数据表,结果就悲剧了
package com.springboot.chapter7.service.impl;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.springboot.chapter7.dao.UserDao;
import com.springboot.chapter7.pojo.User;
import com.springboot.chapter7.service.UserService;/**** imports ****/
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao = null;// 插入用户,最后MyBatis会回填id,取结果id缓存用户@Override@Transactional@CachePut(value = "redisCache", key = "'redis_user_'+#result.id")public User insertUser(User user) {userDao.insertUser(user);return user;}// 获取id,取参数id缓存用户@Override@Transactional@Cacheable(value = "redisCache", key = "'redis_user_'+#id")public User getUser(Long id) {return userDao.getUser(id);}// 更新数据后,充值缓存,使用condition配置项使得结果返回为null,不缓存@Override@Transactional@CachePut(value = "redisCache", condition = "#result != 'null'", key = "'redis_user_'+#id")public User updateUserName(Long id, String userName) {// 此处调用getUser方法,该方法缓存注解失效,// 所以这里还会执行SQL,将查询到数据库最新数据User user = this.getUser(id);if (user == null) {return null;}user.setUserName(userName);userDao.updateUser(user);return user;}// 命中率低,所以不采用缓存机制@Override@Transactionalpublic List<User> findUsers(String userName, String note) {return userDao.findUsers(userName, note);}// 移除缓存@Override@Transactional@CacheEvict(value = "redisCache", key = "'redis_user_'+#id", beforeInvocation = false)public int deleteUser(Long id) {return userDao.deleteUser(id);}
}
就是insertUser方法时,使用的@CachePut将插入到mysql数据库的t_user数据表的数据,同时缓存到redis
建表:t_user(这里复制spring_boot_chapter10数据库的t_user)
spring_boot_chapter10数据库的t_user的建表语句:
drop table if exists user;
create table t_user(id bigint(100) primary key auto_increment,
user_name varchar(20) default null,note varchar(500) default null)
engine=INNODB,default charset=utf8;
建表后的表结构和数据:
现在要创建spring_boot_chapter7数据库的t_user表,由于数据表结构相同,所以直接使用复制语句:
-- 复制spring_boot_chapter10数据库的t_user表,创建spring_boot_chapter7数据库t_user表,会复制数据表结构和数据。
-- 但是复制的表之后,查看建表语句还是有一些差异(有风险)
drop table if exists t_user;
create table t_user select * from spring_boot_chapter10.t_user;
然后查看复制好的数据表:
发现数据结构和表中数据时一样的
现在来测试insertUser()方法,在插入一条语句后
package com.springboot.chapter7.controller;import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.springboot.chapter7.pojo.User;
import com.springboot.chapter7.service.UserService;/****imports ****/
@Controller
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService = null;@RequestMapping("/getUser")@ResponseBodypublic User getUser(Long id) {return userService.getUser(id);}@RequestMapping("/insertUser")@ResponseBodypublic User insertUser(String userName, String note) {User user = new User();user.setUserName(userName);user.setNote(note);userService.insertUser(user);return user;}@RequestMapping("/findUsers")@ResponseBodypublic List<User> findUsers(String userName, String note) {return userService.findUsers(userName, note);}@RequestMapping("/updateUserName")@ResponseBodypublic Map<String, Object> updateUserName(Long id, String userName) {User user = userService.updateUserName(id, userName);boolean flag = user != null;String message = flag? "更新成功" : "更新失败";return resultMap(flag, message);}@RequestMapping("/deleteUser")@ResponseBodypublic Map<String, Object> deleteUser(Long id) {int result = userService.deleteUser(id);boolean flag = result == 1;String message = flag? "删除成功" : "删除失败";return resultMap(flag, message);}private Map<String, Object> resultMap(boolean success, String message) {Map<String, Object> result = new HashMap<String, Object>();result.put("success", success);result.put("message", message);return result;}
}
使用controller测试insertUser()方法,插入数据:
启动sprigboot项目:
浏览器地址输入:http://localhost:8896/user/insertUser?userName==罗山仔¬e=高级java工程师
浏览器响应的json数据,返回一个user对象,但是id的值却是null
现在查看mysql数据库:
查看已经成功插入,但是id=0
现在查看redis数据库,看一下是不是也缓存成功:
发现缓存到redis的键(由redis_user_与id拼接的字符串),发现id也是null
那么为什么会这样的?
问题就是出现在复制语句上,复制语句虽然复制了其他数据表的结构和数据,但是查看chapter7数据库的t_user建表语句会发现差异:
可以看到建表语句与chapter10的t_user建表语句不同,复制了结构和数据,但是并不是完全复制的建表语句
chapter7的t_user建表语句中id没有声明为主键,同时自增也没有了,替代成了default 0,所以每次插入数据,id都是0
所以,需要对chapter7的t_user建表语句做一些修改:
然后运行修改语句,加上主键和自增,然后再进行测试,一切正常:
id已经是4了,查看mysql数据库中插入的数据:
而且之前插入的罗山仔的id也有0变成了2
再查看redis
重新缓存了redis_user_4(redis的键),之前的那个键redis_user_null应该是缓存过期了,刷新之后没了,只剩下redis_user_4
ok,就总结到这里,所以复制表时,虽然方便,,但是也要留意一些坑及风险。所以上边用到的直接复制表结构和数据的语句是有风险的,因此如果要直接从其他数据库复制数据表,下边这样使用是安全的(不会没了主键及自增或者没了索引):
-- 使用其他的复制数据表的语句(复制数据表结构),这种复制语句是安全的,建表语句与spring_boot_chapter10.t_user
-- 的一致
create table t_user like spring_boot_chapter10.t_user;-- 复制表数据
insert into t_user select * FROM spring_boot_chapter10.t_user;
注意:Oracle使用复制语句:
create table t_user as select * FROM spring_boot_chapter10.t_user;
也会出现同样的问题,只复制了数据结构和数据,主键和索引等信息不回复制。
mysql数据库复制数据表时的风险相关推荐
- MySQL数据库、数据表和字段字符集查询、修改和配置
一.设置编码 LINUX 修改vi/etc/my.cnf WINDOWS my.ini 在[client]下添加 default-character-set=utf8 在[mysqld]下添加 ...
- php如何在mysql数据库里创建表_php创建mysql数据库以及数据表
php创建mysql数据库以及数据表 用php链接到mysqli,成功后利用,mysqli_query()创建数据库以及数据表. $con = mysqli_connect("localho ...
- MySQL数据库与数据表的创建
MySQL数据库与数据表的创建 文章目录 MySQL数据库与数据表的创建 前言 一.创建数据库 二.使用数据库 三.创建数据表 前言 MySQL的介绍 什么叫数据库: 作用:存储数据,能够长期保存(断 ...
- 从零开始学 MySQL —数据库和数据表操作
前言 今天我们学习下核心的内容,学习并实践如何对数据库表和表中的内容做修改,删除,重命名等操作.(想看看周末还有多少爱学习的小伙伴,你们在哪里呀,O(∩_∩)O哈哈~) 1.目录 数据库操作:删除数 ...
- 右键计算机管理显示目录名称无效,win10系统打开数据库的数据表时显示“目录名称无效”的恢复方案...
有关win10系统打开数据库的数据表时显示"目录名称无效"的操作方法想必大家有所耳闻.但是能够对win10系统打开数据库的数据表时显示"目录名称无效"进行实际操 ...
- 6.MySQL数据库与数据表操作
数据库的操作:数据库创建 :数据库删除 数据表的操作:数据表的创建:数据表的修改 (表结构) :数据表的删除 数据库的操作 1.数据库的创建 # 链接mysql数据库后,进入mysql后可以操作数据 ...
- Mysql数据库和数据表的创建和信息更改的常用指令
文章目录 数据库和数据表的创建和信息更改 后续小实验做准备 一. 关于数据库和数据表的其它操作 1)数据库 ①创建数据库 ②显示目前所有的数据库 ③数据库重命名 2.1 先创建新库: 2.2 使用`R ...
- oracle跨数据库复制数据表-dblink
-一.最近有一个这样的需求,之前的数据库(部署在4.9),进程不足,需要迁移 到新的数据库(2.77),包括表结构和表数据,一个一个复制着实比较麻烦,在网上百度了下,才知道有dblink这种实现方式, ...
- MySQL数据库及数据表的修改
1.1修改数据库 修改数据库(mydatabase)默认字符集和校对规则,修改结果如下图所示: 1.2删除数据库 drop database mydatabase; 2.1修改表 (1)修改表结构 例 ...
最新文章
- Nginx日志格式设置
- python web框架介绍对比
- python中文软件-Python
- Python 标准库 —— zipfile(读取 zip 文件)
- wpf 用户自定义事件传参
- SAP中添加自定义菜单
- 四、“一场跨越时空持续数世纪的对话”
- html div剩下高度设置,使div填充剩余屏幕空间的高度
- go:系统参数or函数--未完
- 16、java中的集合(3)
- iis运行原理 Asp.Net详解IIS内部运行原理
- 谷歌承诺未来三年将支付10亿美元新闻费用
- linux中哪一个标记可以作为子进程,linux系统编程试卷(答案)
- ARC 环境下 dealloc 的使用误区
- ZooKeeper 会话的秘密
- TOGAF 9 Certification 有用书签
- unity开宝箱动画_Unity动画库插件iTween介绍
- 完全用 GNU/Linux 工作(原版)
- 无法关闭计算机xp,WindowsXP电脑无法关机的解决方法
- 【2020年高被引学者】 梅宏 北京大学