Supponiamo di aver correttamente configurato jpa backed by hibernate (4.3.11) in primavera (4.2.7). La cache di primo livello di ibernazione è abilitata. Usiamo transazioni dichiarative. Abbiamo OuterBeanSpring @Transactional (Propagation.NEVER) dovrebbe creare una sessione di sospensione?
@Service
public class OuterBean {
@Resource
private UserDao userDao;
@Resource
private InnerBean innerBean;
@Transactional(propagation = Propagation.NEVER)
public void withoutTransaction(){
User user = userDao.load(1l);
System.out.println(user.getName());//return userName
innerBean.withTransaction();
user = userDao.load(1l);
System.out.println(user.getName());//return userName instead of newUserName
}
}
E InnerBean che viene chiamato da OuterBean:
@Service
public class InnerBean {
@Resource
private UserDao userDao;
@Transactional
public void withTransaction(){
User user = userDao.load(1l);
user.setName("newUserName");
}
}
E 'un comportamento corretto che il metodo user.getName()
nel OuterBean restituisce lo stesso valore due volte (la seconda volta è dopo aggiornare il nome nel database)?
In altre parole è vero comportamento corretto che @Transactional(propagation = Propagation.NEVER)
crea hibernate sessione per il metodo withoutTransaction()
che provoca che in seconda convocazione user.getName()
legge dalla cache di primo livello di ibernazione invece di database?
EDIT
Per spiegare problema più mi Attaché traccia dalla creazione di sessioni Hibernate
TRACE org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl - Opening Hibernate Session. tenant=null, [email protected]
TRACE org.hibernate.internal.SessionImpl - Opened session at timestamp: 14689173439
TRACE org.hibernate.internal.SessionImpl - Setting flush mode to: AUTO
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
userName
TRACE org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl - Opening Hibernate Session. tenant=null, [email protected]
TRACE org.hibernate.internal.SessionImpl - Opened session at timestamp: 14689173439
TRACE org.hibernate.internal.SessionImpl - Setting flush mode to: AUTO
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Automatically flushing session
TRACE org.hibernate.internal.SessionImpl - before transaction completion
TRACE org.hibernate.internal.SessionImpl - after transaction completion
TRACE org.hibernate.internal.SessionImpl - Closing session
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
userName
TRACE org.hibernate.internal.SessionImpl - Closing session
Ora confrontiamo traccia quando rimuovo @Transactional(propagation = Propagation.NEVER)
TRACE org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl - Opening Hibernate Session. tenant=null, [email protected]
TRACE org.hibernate.internal.SessionImpl - Opened session at timestamp: 14689203905
TRACE org.hibernate.internal.SessionImpl - Setting flush mode to: AUTO
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Closing session
userName
TRACE org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl - Opening Hibernate Session. tenant=null, [email protected]
TRACE org.hibernate.internal.SessionImpl - Opened session at timestamp: 14689203905
TRACE org.hibernate.internal.SessionImpl - Setting flush mode to: AUTO
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Automatically flushing session
TRACE org.hibernate.internal.SessionImpl - before transaction completion
TRACE org.hibernate.internal.SessionImpl - after transaction completion
TRACE org.hibernate.internal.SessionImpl - Closing session
TRACE org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl - Opening Hibernate Session. tenant=null, [email protected]
TRACE org.hibernate.internal.SessionImpl - Opened session at timestamp: 14689203906
TRACE org.hibernate.internal.SessionImpl - Setting flush mode to: AUTO
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
TRACE org.hibernate.internal.SessionImpl - Closing session
newUserName
Si prega di notare quando Tralascio @Transactional(propagation = Propagation.NEVER)
sessione separata è creta per ogni invocazione del metodo da parte dell'utente.
Quindi la mia domanda può essere formulata anche come Non dovrebbe essere @Transactional(propagation = Propagation.NEVER)
implementato in primavera come custode che ci impedisce di utilizzare accidentalmente la transazione, senza alcun effetto collaterale (creazione di sessione)?
in withTransaction dovresti chiamare userDao.merge (utente) per vedere le modifiche in user.getName() – mommcilo
Non capisco come chiamare 'userDao.merge (utente)' potrebbe aiutare. Dopo l'invocazione 'withTransaction()' newUserName è correttamente inserito nel database. Il problema è che all'interno di 'withoutTransaction()' seconda chiamata di 'user.getName()' ** usa la cache di primo livello in ibernazione ** (a causa di '@Transactional (propagation = Propagation.NEVER)' crea una sessione di ibernazione) invece di ottenere newUserName database di moduli diretti. – snieguu
hibernate utilizza sempre la cache di primo livello, a meno che non venga cancellata. –