spring 线程安全 数据同步化的问题

时间:2021-06-15 23:37:12
是这样的.
数据库中有1000条数据.
现在有10个财务.
每个财务请求获取10条数据.


我为了防止这10个财务在同时获得一样的数据.
我想问一下spring有这样的机制嘛?

就是说同时10个人发了10个请求过来.

但是action只有一个而且action是一个一个处理请求.

如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个.
以此类推.

spring可以这样设置吗?

如果不能这样的话我只能手动去同步了.

27 个解决方案

#1


好像没有同步请求的,不知道你有没有试过在Service层得查询业务上设置方法同步呢?应为Service是单例的,即使10个请求同时发生,在Service层同一时刻只有一个请求能进入查询业务。这样应该就能实现同步了吧。

#2


引用 1 楼  的回复:
好像没有同步请求的,不知道你有没有试过在Service层得查询业务上设置方法同步呢?应为Service是单例的,即使10个请求同时发生,在Service层同一时刻只有一个请求能进入查询业务。这样应该就能实现同步了吧。



这不行吧.

#3


引用楼主  的回复:
如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个.
以此类推.


没有直接这样的机制,不过Spring对于bean默认都是单例模式,所以你只要在函数上增加一个 synchronized 关键字,就全部都同步掉了。

#4


EJB

@Singleton
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Service implements ServiceLocal {
    @Override
    @Lock(LockType.WRITE)
    public void doSomething() {
    
    }
}

#5


引用 3 楼  的回复:
引用楼主  的回复:
如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个.
以此类推.


没有直接这样的机制,不过Spring对于bean默认都是单例模式,所以你只要在函数上增加一个 synchronized 关键字,就全部都同步掉了。


我刚才也想过这种形式.

就是bean本身就是单例的
然后在方法中增加synchronized 同步化
但是他真的能做到我在帖子里说到的那种吗?

我有点怀疑.所以来问问大家.

#6


引用 5 楼  的回复:
但是他真的能做到我在帖子里说到的那种吗?

只要肯定是单例,就没问题。
如果你无法确定是单例,那么就让该函数再调用一个 private static synchronized xxoo()


不过,我重新看了下你的问题,我觉得可能存在一个误区:
“如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个”
并不等同于:
“防止这10个财务在同时获得一样的数据”


因为即便你轮流执行10次:Select Top 10 * From 表; 实际上每次你还是得到相同的结果啊。

#7


给你的Controller类 写个空构造方法 , 打个断点。

看每次请求的时候,是否会实例化。

#8


同步你的service方法就可以了

#9


引用 6 楼  的回复:
引用 5 楼  的回复:
但是他真的能做到我在帖子里说到的那种吗?

只要肯定是单例,就没问题。
如果你无法确定是单例,那么就让该函数再调用一个 private static synchronized xxoo()


不过,我重新看了下你的问题,我觉得可能存在一个误区:
“如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个”
并不等同……


我取了10条数据之后会修改状态.

如:我要查询状态==1的.
等第一个人获取到数据之后我会把状态改成==2

第二个人来查询的时候还是以状态==1来查询.

这样的话应该是没问题的吧.

#10


引用 9 楼  的回复:
如:我要查询状态==1的.
等第一个人获取到数据之后我会把状态改成==2

哦,如果这样是没问题的。

其实如果你把这个过程做为一个完整事务来处理的话,数据库层面都可以控制住相互之间不冲突。

#11


交给事务吧,事务的四个特性保证完成任务。

#12


引用 10 楼  的回复:
引用 9 楼  的回复:
如:我要查询状态==1的.
等第一个人获取到数据之后我会把状态改成==2

哦,如果这样是没问题的。

其实如果你把这个过程做为一个完整事务来处理的话,数据库层面都可以控制住相互之间不冲突。


【完整事务来处理】什么意思啊?

数据库层面都可以控制住相互之间不冲突?
又啥意思啊?还有别的方法嘛?说说呗.

#13


楼主对数据库事务不太熟悉么?

如果是JDBC的话,首先关闭自动提交,然后做Select数据时:
  Select Top 10 * From ... For Update
然后对ResultSet进行修改(updateXXOO),最后 commit();

数据库为了保证事务一致性,会把你所选择出来的记录集锁定住(行锁或表锁),这样就控制住并发了。

#14


我用的Struts2+Spring+Hibernate

#15


引用 13 楼  的回复:
楼主对数据库事务不太熟悉么?

如果是JDBC的话,首先关闭自动提交,然后做Select数据时:
  Select Top 10 * From ... For Update
然后对ResultSet进行修改(updateXXOO),最后 commit();

数据库为了保证事务一致性,会把你所选择出来的记录集锁定住(行锁或表锁),这样就控制住并发了。


这个是可以的.我的框架里面带着事物控制的.如果出错会全部回滚.
我用的hibernate+杭锁就可以了.

#16


http://wangxr66.iteye.com/blog/1469077

我看到这篇文章中最后说道了一句话
"在Struts2与Spring集成时,配置Action的Bean时一定记得加上scope属性,值为:prototype,否则会有线程安全问题。 "


我要是把他设置成单例的话会有线程安全问题吗?

我有点蒙了.

#17


引用 16 楼  的回复:
我要是把他设置成单例的话会有线程安全问题吗?


它说的是Action的“Bean”,如果所有请求都共享一个“Bean”,那不是死定了。。。

#18


引用 17 楼  的回复:
引用 16 楼  的回复:
我要是把他设置成单例的话会有线程安全问题吗?


它说的是Action的“Bean”,如果所有请求都共享一个“Bean”,那不是死定了。。。


晕...下我一跳...我把他的话看成了Action...如果吧Action设置成了prototype的话不就没啥用了嘛...

我在在数据查询和更新的时候增加了hibernate事物,就怕在做更新数据库状态操作的时候出现错误...

不过估计应该不会出错误...

action已经是单例了在加上synchronized

已经可以了

万一出现错误了还有事物可以去控制回滚一下...

这就足够了吧.

#19


可以使用Spring+jms+queue

#20


为什么不能获得同样的数据?

我没看出来你的业务场景,以及可预见的代码中存在线程安全问题

#21


引用 20 楼  的回复:
为什么不能获得同样的数据?

我没看出来你的业务场景,以及可预见的代码中存在线程安全问题


如果获得同样的数据的话多个财务对一条数据做处理的话,首先工作重复了,而且最后如果出错了
也不好找到相应的责任人.

所以要避免数据被同时操作.

#22


引用 18 楼  的回复:
这就足够了吧.


理论上是绝对够了的。

不过我补充下:
数据库层面的控制是最合理且安全的,而且基本上就以数据库实现为准。
synchronized的潜在问题是:集群。如果你的部署环境是集群环境,那么synchronized可没法在多个JVM之间保证同步;所以你看到,为啥我说数据库层面控制才是最安全的。

所以,为了避免编码级的疏漏,你要故意做些测试,控制好两个请求同时去操作数据库(比如在Select之后增加Sleep(10000),然后再做其它处理,然后继续Sleep(10000),然后再提交)。

关键性设计和实现必须得到验证,否则从技术人员角度来说,是不严谨的做事方法。

#23


引用 22 楼  的回复:
引用 18 楼  的回复:
这就足够了吧.


理论上是绝对够了的。

不过我补充下:
数据库层面的控制是最合理且安全的,而且基本上就以数据库实现为准。
synchronized的潜在问题是:集群。如果你的部署环境是集群环境,那么synchronized可没法在多个JVM之间保证同步;所以你看到,为啥我说数据库层面控制才是最安全的。

所以,为了避免编码级的疏漏,你要故意做些……


我这里暂时不会集群.

而且我加了hibernate的事物如果出现错误了就直接回滚了,不返回给页面数据了.而是提示他有错误了.

数据库方面实现的话要如何实现呢?我这里用的是mysql

简单提一下吧谢谢

#24


数据库层面控制就是我13楼说的,Select的时候就要加锁。

不过我对Hibernate不太熟悉,没研究过怎么实现选择时加锁。

#25


引用 24 楼  的回复:
数据库层面控制就是我13楼说的,Select的时候就要加锁。

不过我对Hibernate不太熟悉,没研究过怎么实现选择时加锁。


哦```知道了

我研究一下...看看在数据库层面怎么弄...

谢了...

#26


数据同时操作可以使用乐观锁或者悲观锁就行了,没必要这样进行同步的

#27


引用 26 楼  的回复:
数据同时操作可以使用乐观锁或者悲观锁就行了,没必要这样进行同步的


我了解一下

回头再开个帖子大家聊聊

这个锁的问题吧.

#1


好像没有同步请求的,不知道你有没有试过在Service层得查询业务上设置方法同步呢?应为Service是单例的,即使10个请求同时发生,在Service层同一时刻只有一个请求能进入查询业务。这样应该就能实现同步了吧。

#2


引用 1 楼  的回复:
好像没有同步请求的,不知道你有没有试过在Service层得查询业务上设置方法同步呢?应为Service是单例的,即使10个请求同时发生,在Service层同一时刻只有一个请求能进入查询业务。这样应该就能实现同步了吧。



这不行吧.

#3


引用楼主  的回复:
如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个.
以此类推.


没有直接这样的机制,不过Spring对于bean默认都是单例模式,所以你只要在函数上增加一个 synchronized 关键字,就全部都同步掉了。

#4


EJB

@Singleton
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Service implements ServiceLocal {
    @Override
    @Lock(LockType.WRITE)
    public void doSomething() {
    
    }
}

#5


引用 3 楼  的回复:
引用楼主  的回复:
如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个.
以此类推.


没有直接这样的机制,不过Spring对于bean默认都是单例模式,所以你只要在函数上增加一个 synchronized 关键字,就全部都同步掉了。


我刚才也想过这种形式.

就是bean本身就是单例的
然后在方法中增加synchronized 同步化
但是他真的能做到我在帖子里说到的那种吗?

我有点怀疑.所以来问问大家.

#6


引用 5 楼  的回复:
但是他真的能做到我在帖子里说到的那种吗?

只要肯定是单例,就没问题。
如果你无法确定是单例,那么就让该函数再调用一个 private static synchronized xxoo()


不过,我重新看了下你的问题,我觉得可能存在一个误区:
“如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个”
并不等同于:
“防止这10个财务在同时获得一样的数据”


因为即便你轮流执行10次:Select Top 10 * From 表; 实际上每次你还是得到相同的结果啊。

#7


给你的Controller类 写个空构造方法 , 打个断点。

看每次请求的时候,是否会实例化。

#8


同步你的service方法就可以了

#9


引用 6 楼  的回复:
引用 5 楼  的回复:
但是他真的能做到我在帖子里说到的那种吗?

只要肯定是单例,就没问题。
如果你无法确定是单例,那么就让该函数再调用一个 private static synchronized xxoo()


不过,我重新看了下你的问题,我觉得可能存在一个误区:
“如:处理第一个的时候其他9个都处于等待的状态.只有第一个从action中出去了,才接待第二个”
并不等同……


我取了10条数据之后会修改状态.

如:我要查询状态==1的.
等第一个人获取到数据之后我会把状态改成==2

第二个人来查询的时候还是以状态==1来查询.

这样的话应该是没问题的吧.

#10


引用 9 楼  的回复:
如:我要查询状态==1的.
等第一个人获取到数据之后我会把状态改成==2

哦,如果这样是没问题的。

其实如果你把这个过程做为一个完整事务来处理的话,数据库层面都可以控制住相互之间不冲突。

#11


交给事务吧,事务的四个特性保证完成任务。

#12


引用 10 楼  的回复:
引用 9 楼  的回复:
如:我要查询状态==1的.
等第一个人获取到数据之后我会把状态改成==2

哦,如果这样是没问题的。

其实如果你把这个过程做为一个完整事务来处理的话,数据库层面都可以控制住相互之间不冲突。


【完整事务来处理】什么意思啊?

数据库层面都可以控制住相互之间不冲突?
又啥意思啊?还有别的方法嘛?说说呗.

#13


楼主对数据库事务不太熟悉么?

如果是JDBC的话,首先关闭自动提交,然后做Select数据时:
  Select Top 10 * From ... For Update
然后对ResultSet进行修改(updateXXOO),最后 commit();

数据库为了保证事务一致性,会把你所选择出来的记录集锁定住(行锁或表锁),这样就控制住并发了。

#14


我用的Struts2+Spring+Hibernate

#15


引用 13 楼  的回复:
楼主对数据库事务不太熟悉么?

如果是JDBC的话,首先关闭自动提交,然后做Select数据时:
  Select Top 10 * From ... For Update
然后对ResultSet进行修改(updateXXOO),最后 commit();

数据库为了保证事务一致性,会把你所选择出来的记录集锁定住(行锁或表锁),这样就控制住并发了。


这个是可以的.我的框架里面带着事物控制的.如果出错会全部回滚.
我用的hibernate+杭锁就可以了.

#16


http://wangxr66.iteye.com/blog/1469077

我看到这篇文章中最后说道了一句话
"在Struts2与Spring集成时,配置Action的Bean时一定记得加上scope属性,值为:prototype,否则会有线程安全问题。 "


我要是把他设置成单例的话会有线程安全问题吗?

我有点蒙了.

#17


引用 16 楼  的回复:
我要是把他设置成单例的话会有线程安全问题吗?


它说的是Action的“Bean”,如果所有请求都共享一个“Bean”,那不是死定了。。。

#18


引用 17 楼  的回复:
引用 16 楼  的回复:
我要是把他设置成单例的话会有线程安全问题吗?


它说的是Action的“Bean”,如果所有请求都共享一个“Bean”,那不是死定了。。。


晕...下我一跳...我把他的话看成了Action...如果吧Action设置成了prototype的话不就没啥用了嘛...

我在在数据查询和更新的时候增加了hibernate事物,就怕在做更新数据库状态操作的时候出现错误...

不过估计应该不会出错误...

action已经是单例了在加上synchronized

已经可以了

万一出现错误了还有事物可以去控制回滚一下...

这就足够了吧.

#19


可以使用Spring+jms+queue

#20


为什么不能获得同样的数据?

我没看出来你的业务场景,以及可预见的代码中存在线程安全问题

#21


引用 20 楼  的回复:
为什么不能获得同样的数据?

我没看出来你的业务场景,以及可预见的代码中存在线程安全问题


如果获得同样的数据的话多个财务对一条数据做处理的话,首先工作重复了,而且最后如果出错了
也不好找到相应的责任人.

所以要避免数据被同时操作.

#22


引用 18 楼  的回复:
这就足够了吧.


理论上是绝对够了的。

不过我补充下:
数据库层面的控制是最合理且安全的,而且基本上就以数据库实现为准。
synchronized的潜在问题是:集群。如果你的部署环境是集群环境,那么synchronized可没法在多个JVM之间保证同步;所以你看到,为啥我说数据库层面控制才是最安全的。

所以,为了避免编码级的疏漏,你要故意做些测试,控制好两个请求同时去操作数据库(比如在Select之后增加Sleep(10000),然后再做其它处理,然后继续Sleep(10000),然后再提交)。

关键性设计和实现必须得到验证,否则从技术人员角度来说,是不严谨的做事方法。

#23


引用 22 楼  的回复:
引用 18 楼  的回复:
这就足够了吧.


理论上是绝对够了的。

不过我补充下:
数据库层面的控制是最合理且安全的,而且基本上就以数据库实现为准。
synchronized的潜在问题是:集群。如果你的部署环境是集群环境,那么synchronized可没法在多个JVM之间保证同步;所以你看到,为啥我说数据库层面控制才是最安全的。

所以,为了避免编码级的疏漏,你要故意做些……


我这里暂时不会集群.

而且我加了hibernate的事物如果出现错误了就直接回滚了,不返回给页面数据了.而是提示他有错误了.

数据库方面实现的话要如何实现呢?我这里用的是mysql

简单提一下吧谢谢

#24


数据库层面控制就是我13楼说的,Select的时候就要加锁。

不过我对Hibernate不太熟悉,没研究过怎么实现选择时加锁。

#25


引用 24 楼  的回复:
数据库层面控制就是我13楼说的,Select的时候就要加锁。

不过我对Hibernate不太熟悉,没研究过怎么实现选择时加锁。


哦```知道了

我研究一下...看看在数据库层面怎么弄...

谢了...

#26


数据同时操作可以使用乐观锁或者悲观锁就行了,没必要这样进行同步的

#27


引用 26 楼  的回复:
数据同时操作可以使用乐观锁或者悲观锁就行了,没必要这样进行同步的


我了解一下

回头再开个帖子大家聊聊

这个锁的问题吧.