Bevor ich das Problem beschreibe, möchte ich einige Prämissen erläutern. Gehen Sie davon aus, dass die Datenbanktransaktion in der Spring-Konfigurationsdatei wie folgt konfiguriert ist:
<bean id="transactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
Jetzt gibt es UserDao und SecurityService:
@Repository public class UserDao { public User getUser() { // Benutzer aus Benutzertabelle abfragen return queryObject("select * from user order by id desc limit 1" } }
@Service @Transactional public class SecurityService { @Autowired private UserDao userDao; public void checkUserInfo() { while(true) { User user = userDao.getUser(); if(user != null && "Tom".equals(user.getName ()) { System.out.println("Tom ist hier" } } } }
Während des Aufrufs der SecurityService#checkUserInfo()-Methode bleiben die über die userDao#getUser()-Methode erhaltenen Daten unverändert. Auch wenn zu diesem Zeitpunkt neue Daten mit dem Namen Tom eingefügt werden, wird die Schleife nicht beendet. Darüber hinaus hilft das Entfernen der @Transactional-Annotation auf SecurityService nicht.
Zuerst dachte ich, dass es ein Problem mit dem Datenbankverbindungspool sein könnte. Dasselbe gilt, wenn er durch Springs eigenen ersetzt wird. Dann habe ich das Connection-Objekt direkt von JdbcTemplate aus aufgerufen und die ursprüngliche JDBC-Methode verwendet, um die Datenbank zu betreiben Zu diesem Zeitpunkt änderten sich die Daten in Echtzeit, daher dachte ich, dass die Spring-Transaktion an den aktuellen Operationsthread gebunden sein sollte. Nachdem ich den Quellcode überprüft hatte, stellte ich in der Methode DataSourceUtils#doGetConnection fest, dass Spring für jede DataSource jedes Threads eine Verbindung erstellt und diese an die Transaktion gebunden hat. Da die tx:annotation-gesteuerte Konfigurationsdatei die Transaktionsbindung auf allen Service-Ebenen (mit @Service annotierte Klassen) durchführt, wird dieselbe Verbindung im selben Thread gebunden, unabhängig davon, ob @Transactional verwendet wird, es werden jedoch keine einfachen Geschäftsvorgänge ausgeführt .
Nach vielen Experimenten und der Suche nach Informationen habe ich endlich die perfekte Lösung gefunden: Fügen Sie einfach die Annotation @Transactional(propagation = Propagation.NOT_SUPPORTED) zur obigen checkUserInfo-Methode hinzu. Natürlich können Sie die Verbindung auch abrufen und den Vorgang manuell ausführen oder das DateUtils-Paket verwenden, um den Vorgang auszuführen.