Spring + Hibernate performance issue (dirty checking)
От: InstantI Украина  
Дата: 23.01.12 09:17
Оценка:
Доброго времени суток. В моем приложении каждую минуту происходит сканирование игровых серверов, с последующим занесением результатов в базу данных. Столкнулся с серьезной проблемой производительности. Занесение результатов в БД (около 2000 записей) занимает ~30 секунд.
Есть следующий код:
@Service
public class ServerScannerImpl implements ServerScanner
{
    @Transactional
    public void process()
    {
        ...
        ... // Здесь код сканирования, далее занесение результата в БД
        handleResult();        
    }  
    
    private void handleResult()
    {
        fillServerInfo(server, info); // Для каждого сервера (примерно 2000) вызывается этот метод
    }
    
    private void fillServerInfo(Server server, ServerInfo info)
    {
        ...
        ...
        Map map = mapService.getMapByHttpName(mapHttpName, game.getId());
        if (map == null)
        {
            map = new Map();
            map.setName(info.getMap());
            map.setGame(game);
            map.setHttpName(mapHttpName);
            mapService.addMap(map);
        }
        server.setMap(map);
        ...
        ...
        serverService.addSever(server);
    }

    @Autowired
    private ServerService serverService;
    
    @Autowired
    private MapService mapService;
}

С помощью профайлера выяснил, что 80% времени выполнения приходится на этот метод:
Map map = mapService.getMapByHttpName(mapHttpName, game.getId());

@Service
@Transactional(readOnly = true)
public class MapServiceImpl implements MapService
{    
    public Map getMapById(Integer id)
    {
        return mapDAO.getMapById(id);
    }
   
    public Map getMapByHttpName(String httpName, Integer gameId)
    {
        return mapDAO.getMapByHttpName(httpName, gameId);
    }    
    
    @Transactional(readOnly = false)
    public void addMap(Map map)
    {
        mapDAO.addMap(map);
    }    
    
    public List<Map> getAllMaps()
    {
        return mapDAO.getAllMaps();
    }    
    
    @Transactional(readOnly = false)
    public void removeMap(Map map)
    {
        mapDAO.removeMap(map);
    }
    
    @Autowired
    private MapDAO mapDAO;
}

По call tree видно, что каждый раз, перед выполнением запроса к базе, происходит dirty checking:
org.hibernate.internal.SessionImpl.autoFlushIfRequired(Set)

А поскольку метод mapService.getMapByHttpName(mapHttpName, game.getId()) вызывается ~2000 раз, то львиная доля времени уходит на dirty checking.
Добавил в MapServiceImpl readOnly = true к аннотации @Transactional, но на ситуацию это не повлияло. Я новичек в этой области, поэтому не представляю как решить эту проблему. Спасибо за помощь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.