mysql如何去掉已经缓存但还未执行的update语句

123456adc 2015-12-30 11:12:03
加精
情况是这样的,服务器的mysql数据库由于数据越来越多经常出现慢查询(最长的查询时间有45秒,有select语句也有update语句),由于这种慢查询的操作,经常导致数据出现异常。比如以下这种情况:

程序有两个线程,分别为上线处理线程和下线处理线程(两个线程分别使用两个mysql连接)
A用户上线,上线处理线程会在user表中将A的status状态设置为1(表示上线);
A用户下线,下线处理线程会将user表中A的 status状态值设置为2(表示下线)。
假如A用户掉线时,此时将 UPDATE user SET status =2 where userid = A 这条语句添加进mysql,但此时由于各种原因吧,这条mysql语句还未真正执行,而此时用户A发现掉线,立即重新登录,此时上线处理线程会将A的status设置为1,假设这条UPDATE user SET status =1 where userid = A语句立刻执行了,然后mysql才执行UPDATE user SET status =2 where userid = A 。这样就造成了用户A实际在线,而数据库记录状态为离线。

遇到这样的问题,我该如何解决?

目前的暂时解决方案是使用心跳包,每次收到A用户的报文就将status置为1,这样虽然可以避免,但增加了写库的负担。
还有一种我设想的方案,就是用户上线时先查数据库缓存的update语句,如果有UPDATE user SET status =2 where user id= A这条,就将其删掉不再执行,不知mysql能不能这样操作。
本人不是DBA,对数据库操作不是太懂。请各位给点意见 。欢迎大家共同讨论

...全文
3275 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
LongRui888 2016-01-12
  • 打赏
  • 举报
回复
我觉得这个还是有办法的,只是你需要去google上搜搜,国外说不定有解决的办法,再就是你是程序员,可以看看mysql的源代码,深入学习,看懂了,直接改改,就能实现你的想法了
psy2182_cn 2016-01-12
  • 打赏
  • 举报
回复
首先,两个线程如果操作相同的表(资源),需要在程序中进行线程同步的,比如加线程锁之类的,另外更新数据库时,可以把条件设为更具体的条件。
sinat_33696610 2016-01-10
  • 打赏
  • 举报
回复
可以的!学习了...
nettman 2016-01-08
  • 打赏
  • 举报
回复
学习了
gaoqi121521 2016-01-08
  • 打赏
  • 举报
回复
学习一下
Cx_轩 2016-01-08
  • 打赏
  • 举报
回复
可以的!学习了....
alienyu0352 2016-01-08
  • 打赏
  • 举报
回复
有多少数据会导致慢查询,有没有考虑过使用内存数据库,速度会快很多。
nettman 2016-01-07
  • 打赏
  • 举报
回复
进来学习下
tianfang 2016-01-04
  • 打赏
  • 举报
回复
1 登录状态放在一个单独的表,mysql支持内存表,登录状态这种业务处理适合使用内存表 2 命令更准确 UPDATE user SET status =2 where userid = A and status =1 3 对mysql优化,增加内存,增加索引
nyhyn 2015-12-31
  • 打赏
  • 举报
回复
像这种登入登出的问题,请求手动时,将user_id放入缓存,一分钟后失效。若上一次请求没处理完,直接返回,提示用户等待。处理完后删除缓存。下一个请求才会处理。这是一种方法,可能不太友好。
LongRui888 2015-12-31
  • 打赏
  • 举报
回复
引用 9 楼 anyliwu 的回复:
[quote=引用 7 楼 yupeigu 的回复:] [quote=引用 6 楼 anyliwu 的回复:] [quote=引用 3 楼 yupeigu 的回复:] 当用户点击登录按钮,发送登录包后,如果验证通过,那么就登录了,在会话状态信息里记录他已经登录。 如果达到超时时间还没有任何的操作,那么就是掉线了。 如果点击了退出按钮,那么就是退出了。 上面是一般的网页系统的处理方法
感谢版主的回答,这个可能还是要优化数据库,45秒的慢查询,时间太长了[/quote] 从时间序列上,应该是先掉线了改为2,然后用户重新登录了改为1,就是 有时间上的先后,能否在表中有字段,表示修改状态修改的时候的时间呢? 每次在update的时候,都去比较一下,如果当前数据的最新修改时间,比掉线update 2的修改时间,还要晚,那么就说明不需要修改了,我觉得如果能加上这么一个判断,就会相对好处理一点。[/quote] 这个可能不行,现在是两条语句都通过不同数据库连接线程缓存到数据库了,只是还没有真正执行,哪条语句先执行不确定[/quote] 你的意思是 用2个不同的线程来处理,那肯定是有点问题的。 我的意思不是说那个语句先执行完成,而是说那个操作先被触发,如果掉线的先被触发,记录这个触发的时间点,比如 2015-12-31 08:00:00 ,而重新登录的操作后被触发,比如是 2015-12-31 08:00:05,,也记录下来。 在进行实际的update操作的时候,通过刚才记录的时间点来判断,是否要进行状态的更新,不管你是用1个,还是2个线程来操作,都不要紧,如果后被触发的登录操作的sql,先运行完,也没有关系。 如果是 登录操作先触发,而掉线操作后被触发,那么可以理解为,这个人登录了,后面又掉线了。
123456adc 2015-12-30
  • 打赏
  • 举报
回复
引用 7 楼 yupeigu 的回复:
[quote=引用 6 楼 anyliwu 的回复:] [quote=引用 3 楼 yupeigu 的回复:] 当用户点击登录按钮,发送登录包后,如果验证通过,那么就登录了,在会话状态信息里记录他已经登录。 如果达到超时时间还没有任何的操作,那么就是掉线了。 如果点击了退出按钮,那么就是退出了。 上面是一般的网页系统的处理方法
感谢版主的回答,这个可能还是要优化数据库,45秒的慢查询,时间太长了[/quote] 从时间序列上,应该是先掉线了改为2,然后用户重新登录了改为1,就是 有时间上的先后,能否在表中有字段,表示修改状态修改的时候的时间呢? 每次在update的时候,都去比较一下,如果当前数据的最新修改时间,比掉线update 2的修改时间,还要晚,那么就说明不需要修改了,我觉得如果能加上这么一个判断,就会相对好处理一点。[/quote] 这个可能不行,现在是两条语句都通过不同数据库连接线程缓存到数据库了,只是还没有真正执行,哪条语句先执行不确定
LongRui888 2015-12-30
  • 打赏
  • 举报
回复
引用 6 楼 anyliwu 的回复:
[quote=引用 3 楼 yupeigu 的回复:] 当用户点击登录按钮,发送登录包后,如果验证通过,那么就登录了,在会话状态信息里记录他已经登录。 如果达到超时时间还没有任何的操作,那么就是掉线了。 如果点击了退出按钮,那么就是退出了。 上面是一般的网页系统的处理方法
感谢版主的回答,这个可能还是要优化数据库,45秒的慢查询,时间太长了[/quote] 从时间序列上,应该是先掉线了改为2,然后用户重新登录了改为1,就是 有时间上的先后,能否在表中有字段,表示修改状态修改的时候的时间呢? 每次在update的时候,都去比较一下,如果当前数据的最新修改时间,比掉线update 2的修改时间,还要晚,那么就说明不需要修改了,我觉得如果能加上这么一个判断,就会相对好处理一点。
LongRui888 2015-12-30
  • 打赏
  • 举报
回复
另外,45的慢查询,找个确实需要进行优化,但是要先解决这个逻辑上的问题,然后再看看哪些慢查询,能不能优化的,一般索引就能启动优化的效果。
123456adc 2015-12-30
  • 打赏
  • 举报
回复
引用 3 楼 yupeigu 的回复:
当用户点击登录按钮,发送登录包后,如果验证通过,那么就登录了,在会话状态信息里记录他已经登录。 如果达到超时时间还没有任何的操作,那么就是掉线了。 如果点击了退出按钮,那么就是退出了。 上面是一般的网页系统的处理方法
感谢版主的回答,这个可能还是要优化数据库,45秒的慢查询,时间太长了
123456adc 2015-12-30
  • 打赏
  • 举报
回复
引用 2 楼 yupeigu 的回复:
还有一种我设想的方案,就是用户上线时先查数据库缓存的update语句,如果有UPDATE user SET status =2 where user id= A这条,就将其删掉不再执行,不知mysql能不能这样操作。 你的这个想法是不太可能实现的,而且就算能实现,未免也太复杂了点,相当于要判断如果子在某种情况下,就把将要执行的sql去掉,不执行了。 这个所谓用户上线和下线,应该都是在应用服务器上的会话信息里报错的,也就是说掉不掉线,首先是应用检测到了,或者是当用户有某项操作时,应用做出的反应,而数据库只是执行应用发送过来的sql而已。
是这样的,应用里的确知道当前用户是在线的,也向数据库里写了在线标志,关键就是这两条语句执行顺序不确定,这就导致了web界面显示用户状态可能是离线
123456adc 2015-12-30
  • 打赏
  • 举报
回复
引用 1 楼 congya001 的回复:
楼主你好 我只知道去掉缓存的方法 MySQL的FLUSH可以清理mysql数据库缓存数据 MySQL的FLUSH句法(清除或者重新加载内部缓存) FLUSH flush_option [,flush_option],如果你想要清除一些MySQL使用内部缓存,你应该使用FLUSH命令。为了执行FLUSH,你必须有reload权限。 flush_option 可以是下列任何东西: HOSTS 这个用的最多,经常碰见。主要是用来清空主机缓存表。如果你的某些主机改变IP数字,或如果你得到错误消息Host ... isblocked,你应该清空主机表。当在连接MySQL服务器时,对一台给定的主机有多于 max_connect_errors个错误连续不断地发生,MySQL为了安全的需要将会阻止该主机进一步的连接请求。清空主机表允许主机再尝试连接。 LOGS 关闭当前的二进制日志文件并创建一个新文件,新的二进制日志文件的名字在当前的二进制文件的编号上加1。 PRIVILEGES 这个也是经常使用的,每当重新赋权后,为了以防万一,让新权限立即生效,一般都执行一把,目地是从数据库授权表中重新装载权限到缓存中。 TABLES 关闭所有打开的表,同时该操作将会清空查询缓存中的内容。 FLUSH TABLES WITH READ LOCK 关闭所有打开的表,同时对于所有数据库中的表都加一个读锁,直到显示地执行unlock tables,该操作常常用于数据备份的时候。解锁的语句就是unlock tables。 FLUSH TABLES WITH READ LOCK对于数据库是全局的表锁定,如果只想锁定几个表,可以用LOCK TABLES tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE} 。这个命令同样需要unlock tables来解锁。 read-lock: 允许其他并发的读请求,但阻塞写请求,即可以同时读,但不允许任何写。也叫共享锁。write-lock: 不允许其他并发的读和写请求,是排他的(exclusive)。也叫独占锁 STATUS 重置大多数状态变量到0。 MASTER 删除所有的二进制日志索引文件中的二进制日志文件,重置二进制日志文件的索引文件为空,创建一个新的二进制日志文件,不过这个已经不推荐使用,改成reset master 了。可以想象,以前自己是多土啊,本来一条简单的命令就可以搞定的,却要好几条命令来,以前的做法是先查出来当前的二进制日志文件名,再用purge 操作。 QUERY CACHE 重整查询缓存,消除其中的碎片,提高性能,但是并不影响查询缓存中现有的数据,这点和Flush table 和Reset Query Cache(将会清空查询缓存的内容)不一样的。 SLAVE 类似于重置复制吧,让从数据库忘记主数据库的复制位置,同时也会删除已经下载下来的relay log,与Master一样,已经不推荐使用,改成Reset Slave了。这个也很有用的。 一般来讲,Flush操作都会记录在二进制日志文件中,但是FLUSH LOGS、FLUSH MASTER、FLUSH SLAVE、FLUSH TABLES WITH READ LOCK不会记录,因此上述操作如果记录在二进制日志文件中话,会对从数据库造成影响。
首先非常感谢你的回答,但这个据我所知只是清空数据库缓存的查询数据,比如两条一样的查询语句,第二次查询时会直接使用第一次查询时缓存的内容
LongRui888 2015-12-30
  • 打赏
  • 举报
回复
当用户点击登录按钮,发送登录包后,如果验证通过,那么就登录了,在会话状态信息里记录他已经登录。 如果达到超时时间还没有任何的操作,那么就是掉线了。 如果点击了退出按钮,那么就是退出了。 上面是一般的网页系统的处理方法
LongRui888 2015-12-30
  • 打赏
  • 举报
回复
还有一种我设想的方案,就是用户上线时先查数据库缓存的update语句,如果有UPDATE user SET status =2 where user id= A这条,就将其删掉不再执行,不知mysql能不能这样操作。 你的这个想法是不太可能实现的,而且就算能实现,未免也太复杂了点,相当于要判断如果子在某种情况下,就把将要执行的sql去掉,不执行了。 这个所谓用户上线和下线,应该都是在应用服务器上的会话信息里报错的,也就是说掉不掉线,首先是应用检测到了,或者是当用户有某项操作时,应用做出的反应,而数据库只是执行应用发送过来的sql而已。
文修 2015-12-30
  • 打赏
  • 举报
回复
楼主你好 我只知道去掉缓存的方法 MySQL的FLUSH可以清理mysql数据库缓存数据 MySQL的FLUSH句法(清除或者重新加载内部缓存) FLUSH flush_option [,flush_option],如果你想要清除一些MySQL使用内部缓存,你应该使用FLUSH命令。为了执行FLUSH,你必须有reload权限。 flush_option 可以是下列任何东西: HOSTS 这个用的最多,经常碰见。主要是用来清空主机缓存表。如果你的某些主机改变IP数字,或如果你得到错误消息Host ... isblocked,你应该清空主机表。当在连接MySQL服务器时,对一台给定的主机有多于 max_connect_errors个错误连续不断地发生,MySQL为了安全的需要将会阻止该主机进一步的连接请求。清空主机表允许主机再尝试连接。 LOGS 关闭当前的二进制日志文件并创建一个新文件,新的二进制日志文件的名字在当前的二进制文件的编号上加1。 PRIVILEGES 这个也是经常使用的,每当重新赋权后,为了以防万一,让新权限立即生效,一般都执行一把,目地是从数据库授权表中重新装载权限到缓存中。 TABLES 关闭所有打开的表,同时该操作将会清空查询缓存中的内容。 FLUSH TABLES WITH READ LOCK 关闭所有打开的表,同时对于所有数据库中的表都加一个读锁,直到显示地执行unlock tables,该操作常常用于数据备份的时候。解锁的语句就是unlock tables。 FLUSH TABLES WITH READ LOCK对于数据库是全局的表锁定,如果只想锁定几个表,可以用LOCK TABLES tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE} 。这个命令同样需要unlock tables来解锁。 read-lock: 允许其他并发的读请求,但阻塞写请求,即可以同时读,但不允许任何写。也叫共享锁。write-lock: 不允许其他并发的读和写请求,是排他的(exclusive)。也叫独占锁 STATUS 重置大多数状态变量到0。 MASTER 删除所有的二进制日志索引文件中的二进制日志文件,重置二进制日志文件的索引文件为空,创建一个新的二进制日志文件,不过这个已经不推荐使用,改成reset master 了。可以想象,以前自己是多土啊,本来一条简单的命令就可以搞定的,却要好几条命令来,以前的做法是先查出来当前的二进制日志文件名,再用purge 操作。 QUERY CACHE 重整查询缓存,消除其中的碎片,提高性能,但是并不影响查询缓存中现有的数据,这点和Flush table 和Reset Query Cache(将会清空查询缓存的内容)不一样的。 SLAVE 类似于重置复制吧,让从数据库忘记主数据库的复制位置,同时也会删除已经下载下来的relay log,与Master一样,已经不推荐使用,改成Reset Slave了。这个也很有用的。 一般来讲,Flush操作都会记录在二进制日志文件中,但是FLUSH LOGS、FLUSH MASTER、FLUSH SLAVE、FLUSH TABLES WITH READ LOCK不会记录,因此上述操作如果记录在二进制日志文件中话,会对从数据库造成影响。

56,678

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧