Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SpringMVC:如何确保多个用户能够按顺序调用一个方法_Java_Spring_Spring Mvc_Synchronization - Fatal编程技术网

Java SpringMVC:如何确保多个用户能够按顺序调用一个方法

Java SpringMVC:如何确保多个用户能够按顺序调用一个方法,java,spring,spring-mvc,synchronization,Java,Spring,Spring Mvc,Synchronization,我正在开发一个SpringMVC应用程序,其中我们有一个更新对象内容的方法。此方法需要大量处理,并且可以由多个用户调用以更新同一对象。如何确保方法按照每个用户触发的顺序更新,并且在更新时没有任何用户具有过时数据 服务层方法: @Transactional @Service private GroupNotesServiceImpl implements GroupNotesService{ @Override public String editNoteWithMap(Map&l

我正在开发一个SpringMVC应用程序,其中我们有一个更新对象内容的方法。此方法需要大量处理,并且可以由多个用户调用以更新同一对象。如何确保方法按照每个用户触发的顺序更新,并且在更新时没有任何用户具有过时数据

服务层方法:

@Transactional
@Service
private GroupNotesServiceImpl implements GroupNotesService{
    @Override
    public String editNoteWithMap(Map<String, Object> noteMap) {
        Person person = this.personService.getCurrentlyAuthenticatedUser();
        if ((noteMap != null) && (!noteMap.isEmpty())) {
            int noteId = (Integer) noteMap.get("id");
// How to ensure below object is not stale. 
        GroupNotes databaseNoteObject = this.groupNotesDAO.getGroupNoteById(noteId);
{  // Process the Map }
// Update the object as below :
        this.groupNotesDAO.editGroupNote(databaseNoteObject, databaseNoteObject.getOwnedSectionId());

}
@Repository
@Transactional
public class GroupNotesDAOImpl implements GroupNotesDAO {

    private final SessionFactory sessionFactory;

    @Override
    public GroupNotes editGroupNote(GroupNotes mnotes, int msectionid) {
        Session session = this.sessionFactory.getCurrentSession();
 session.flush();
// I had the lock before, but it started messing around for other updates of associated objects. That was caused by getById also being under lock.
            //  session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(mnotes);
            GroupSection groupSection = (GroupSection) session.get(GroupSection.class, msectionid);
            groupSection.getSectionsnotes().add(mnotes);
            mnotes.setOwnednotes(groupSection);
            GroupNotes savedObject = (GroupNotes) session.merge(mnotes);
            session.merge(groupSection);
            session.flush();
            return savedObject;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

  @Override
    public GroupNotes getGroupNoteById(int id) {
        Session session = this.sessionFactory.getCurrentSession();
        session.flush();
        return (GroupNotes) session.get(GroupNotes.class, id);
    }
}
root-context.xml:

<context:component-scan base-package="com.tooltank.spring">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<context:property-placeholder location="classpath:application.properties"/>

<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close">
    <beans:property name="driverClassName" value="org.postgresql.Driver"/>
    <beans:property name="url"
                    value="jdbc:postgresql://localhost:5432/DBNAME"/>
    <beans:property name="username" value="USERNAME"/>
    <beans:property name="password" value="PASSWORD"/>
    <beans:property name="removeAbandoned" value="true"/>
    <beans:property name="removeAbandonedTimeout" value="20"/>
    <beans:property name="defaultAutoCommit" value="false"/>
</beans:bean>

<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory"
            class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <beans:property name="dataSource" ref="dataSource"/>
    <beans:property name="packagesToScan" value="com.tooltank.spring.model"/>
    <beans:property name="hibernateProperties">
        <beans:props>
            <beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop>
            <beans:prop key="hibernate.show_sql">false</beans:prop>
            <!--   <beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop>-->
            <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
            <beans:prop key="cache.use_second_level_cache">true</beans:prop>
            <beans:prop key="cache.use_query_cache">true</beans:prop>
            <beans:prop key="hibernate.order_updates">true</beans:prop>
            <beans:prop key="show_sql">false</beans:prop>
        </beans:props>
    </beans:property>

</beans:bean>

<beans:bean id="LoginServiceImpl" class="com.tooltank.spring.service.LoginServiceImpl"/>


<task:annotation-driven executor="myExecutor"/>

<task:executor id="myExecutor" pool-size="7-42" queue-capacity="11"/>


<tx:annotation-driven transaction-manager="transactionManager"/>

<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory"/>
</beans:bean>

<cache:annotation-driven/>

<beans:bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
    <beans:property name="caches">
        <beans:set>
            <beans:bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
                        p:name="person"/>
        </beans:set>
    </beans:property>
</beans:bean>

<!-- AppConfiguration for Spring-Data-Redis -->
<beans:bean id="jedisConnFactory"
            class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:usePool="true"/>

<beans:bean id="redisSaveTemplate" class="org.springframework.data.redis.core.RedisTemplate"
            p:connectionFactory-ref="jedisConnFactory"/>

<beans:bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
            p:connectionFactory-ref="jedisConnFactory"/>


org.hibernate.dialogue.postgresql9dialogue
假的
更新
真的
真的
真的
假的

多谢各位

有几种方法可以做到这一点

1。快一点,同步一下

通过同步editNoteWithMap()方法,可以确保只有一个线程访问editNoteWithMap()。然而,如果注释可以在其他地方(其他方法/其他系统)更新,或者如果您担心它可能会导致性能问题,那么syncronized可能不是您想要的神奇帮助

2。通过实现锁定/版本机制,实现长期锁定/版本机制


您可以在便笺记录上创建锁定/版本机制。有几种方法可以实现它,一个例子是在note记录上添加version列。在更新之前,您应该检查记录的版本是否与检索到的版本相同,并决定是重试更新还是更新失败

有几种方法可以做到这一点

1。快一点,同步一下

通过同步editNoteWithMap()方法,可以确保只有一个线程访问editNoteWithMap()。然而,如果注释可以在其他地方(其他方法/其他系统)更新,或者如果您担心它可能会导致性能问题,那么syncronized可能不是您想要的神奇帮助

2。通过实现锁定/版本机制,实现长期锁定/版本机制


您可以在便笺记录上创建锁定/版本机制。有几种方法可以实现它,一个例子是在note记录上添加version列。在更新之前,您应该检查记录的版本是否与检索到的版本相同,并决定是重试更新还是更新失败

如果我理解正确,您的要求可能会有冲突:

方法按每个用户触发的顺序更新,但不更新 更新时,用户的有过时的数据

给定同一实体上按顺序进行的N次同步更新。
第一个将对实体进行udpate。因此,以下更新将使用过时数据更新已更新的实体

如果仅使用
synchronized
实现同步:

  • concurrents更新将按顺序进行,但可以使用过时的数据进行更新
  • 对该方法的所有调用都将同步,即使是针对另一个实体的调用
  • 同步在多个实例上不起作用
如果只实现版本控制

  • 只有一个实体当前版本的更新将成功,其他更新将失败,因为他们尝试更新实体的以前版本
我认为这是有道理的


如果按顺序将需求降低到,则同步将起作用。但在方法上可能过于宽泛。对于这种类型的用例,您可以使用

如果我正确理解,您的需求可能会冲突:

方法按每个用户触发的顺序更新,但不更新 更新时,用户的有过时的数据

给定同一实体上按顺序进行的N次同步更新。
第一个将对实体进行udpate。因此,以下更新将使用过时数据更新已更新的实体

如果仅使用
synchronized
实现同步:

  • concurrents更新将按顺序进行,但可以使用过时的数据进行更新
  • 对该方法的所有调用都将同步,即使是针对另一个实体的调用
  • 同步在多个实例上不起作用
如果只实现版本控制

  • 只有一个实体当前版本的更新将成功,其他更新将失败,因为他们尝试更新实体的以前版本
我认为这是有道理的


如果按顺序将需求降低到,则同步将起作用。但在方法上可能过于宽泛。对于这种类型的用例,您可以使用

是否尝试使该方法同步?如果我们使editNoteWithMap()成为同步方法,您是否有任何顾虑?其他选项是锁定便笺对象。@Rudy:不,现在可以将其同步,并尝试该注释。澄清一下:使用“同步”选项,您现在只能部署应用程序的一个实例(此功能不会中断)。您的应用程序现在不能扩展到一个已部署实例之外。Synchronized只能控制在该Java应用程序上运行的线程。如果您想要跨多个实例工作,那么需要在它们共享的某个点对其进行控制。使用数据库是最常见的方法:每个实例共享同一个数据库。因此,某种类型的数据库锁定(例如@Rudy建议的版本控制方法是一种很好的方法),您是否尝试使该方法同步?如果我们使editNoteWithMap()成为同步方法,您是否有任何顾虑?其他选项是锁定便笺对象。@Rudy:不,现在可以将其同步,尝试该注释。澄清一下:使用同步选项,您现在只能部署一个插件