Ответ 1
Для меня работает следующее:
DataSourceConfig.java
@Bean
public LocalSessionFactoryBean sessionFactory() {
// Link your data source to your session factory
...
}
@Bean("hibernateTxManager")
public HibernateTransactionManager hibernateTxManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
// Link your session factory to your transaction manager
...
}
MyServiceImpl.java
@Service
@Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = "hibernateTxManager", readOnly = true)
public class MyServiceImpl implements MyService {
@Autowired
private MyRepo myRepo;
...
Stream<MyEntity> stream = myRepo.getStream();
// Do your streaming and CLOSE the steam afterwards
...
MyRepoImpl.java
@Repository
@Transactional(propagation = Propagation.MANDATORY, transactionManager = "hibernateTxManager", readOnly = true)
public class MyRepoImpl implements MyRepo {
@Autowired
private SessionFactory sessionFactory;
@Autowired
private MyDataSource myDataSource;
public Stream<MyEntity> getStream() {
return sessionFactory.openStatelessSession(DataSourceUtils.getConnection(myDataSource))
.createNativeQuery("my_query", MyEntity.class)
.setReadOnly(true)
.setFetchSize(1000)
.stream();
}
...
Просто помните, что при потоке вы действительно должны быть осторожны с памятью в момент материализации объекта. Это действительно единственная часть операции, восприимчивая к проблемам в памяти. В моем случае я разбиваю поток на 1000 объектов за один раз, сериализую их с помощью gson и немедленно отправляю их в JMS-брокер. Остальное делает сборщик мусора.
Стоит отметить, что Spring осведомленность о границах транзакций закрывает соединение с дБ в конце, без необходимости явно указывать.