2012-07-04 31 views
0

我正在使用用戶身份驗證的WebSocket服務器中工作。我現在真的不知道如何在請求中存儲這個用戶。我的WebSocket連接可能會保持打開幾個小時,有時它會每分鐘收到100個請求,有時每小時收到2個請求(這是不可預測的)。用戶數據可能會被另一個應用程序改變,這不是我的問題,但它可能是相關的。我使用spring 3和hibernate 3.6.9。跨Web請求管理持久用戶數據

我的問題是:我是否應該使用特定的事務管理,以及如何管理這些用戶數據。

我已經測試2使用案例:

1. 在日誌中加載我的用戶實體和合並(),它在每個請求。我必須合併它,因爲交易在每次請求後都關閉。合併不是一個好的解決方案,因爲它不加載數據庫實體,而是堅持合併的那個。所以如果數據在其他地方更新,它會恢復它們,而不是加載更新的數據。

2. 在登錄時,我只存儲用戶ID,並在每個請求中查找()我的用戶。爲了避免數據庫請求氾濫,我設置了二級緩存,但根據我的sql服務器日誌,hibernate仍然每find()運行一次請求。

下面是一些具體的代碼和配置:

的persistence.xml

<persistence-unit name="greenpacs"> 
<provider>org.hibernate.ejb.HibernatePersistence</provider> 

<exclude-unlisted-classes>false</exclude-unlisted-classes> 
<properties> 
    <property name="hibernate.archive.autodetection" value="class"/> 
    <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> 
    <property name="hibernate.hbm2ddl.auto" value="update"/> 
    <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> 

    <property name="hibernate.show_sql" value="true"/> 
    <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/db"/> 
    <property name="hibernate.connection.user" value="root"/> 
    <property name="hibernate.connection.password" value="password"/> 
    <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> 
</properties> 
</persistence-unit> 

的applicationContext.xml

<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceUnitName" value="greenpacs" /> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean> 

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

用戶實體

@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) 
@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
public class User { 
@Id 
@Column(name = "userId", unique = true, nullable = false) 
private Integer id; 

private String pwd; 

@ManyToMany(fetch = FetchType.EAGER) 
@JoinTable(name = "User_Role", joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "userId") }, inverseJoinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") }) 
private List<Role> roles; 

@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
@JoinColumn(name="id") 
private Person person; 

@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.user", cascade = CascadeType.ALL) 
private List<Pacs> pacs; 

// getter&setter 

的WebSocket監聽

@Component 
public class UserManager implements WampMessageHandler { 

UserService userService; 
//Autowired setter 

    User user; 

@Override 
public void onConnected(WampConnection connection) { 
     //loginmethod return userId 
     user = userService.find(userId); 
    } 

@Transactional 
@Override 
public boolean onMessage(String sessionId, int messageType, Object[] msg) 
     throws BadMessageFormException { 
    user = userService.merge(user); 
      //or 
      user = userService.find(user.getId()); 
      ... 
} 

我UserService只是重定向到EntityManager的方法。

+0

你的第二個解決方案看起來很明顯。如果你的問題是「如何避免這個額外的查詢」,那麼我的問題就是:「這個查詢做了什麼?」? –

+0

沒有額外的查詢它只是爲每個查找hibernate進行查詢,它似乎沒有使用任何緩存。由於關係,查詢很長,但它只不過是一個簡單的「SELECT * FROM User WHERE id =?」。 – Ghetolay

+0

你確定用戶在緩存中嗎?如果用戶可以修改,那麼爲什麼要使用READ_ONLY策略?你有沒有嘗試將hibernate.cache.use_second_level_cache設置爲true?你確定查詢加載用戶的字段,而不僅僅是它的渴望的關聯(沒有被緩存)? –

回答

1

你的第二個解決方案看起來很明顯。您看到對數據庫的查詢,因爲您沒有將hibernate.cache.use_second_level_cache屬性設置爲true