Я использую запланированное задание для обновления моей базы данных следующим образом:
public interface UserRatingManager {
public void updateAllUsers();
}
@Service
public class DefaultUserRatingManager implements UserRatingManager {
@Autowired
UserRatingDAO userRatingDAO;
@Override
@Transactional("txName")
public void updateAllUsers() {
List<String> userIds = userRatingDAO.getAllUserIds();
for (String userId : userIds) {
updateUserRating(userId);
}
}
}
public interface UserRatingDAO extends GenericDAO<UserRating, String> {
public void deleteAll();
public List<String> getAllUserIds();
}
@Repository
public class HibernateUserRatingDAO extends BaseDAO<UserRating, String> implements UserRatingDAO {
@Override
public List<String> getAllUserIds() {
List<String> result = new ArrayList<String>();
Query q1 = getSession().createQuery("Select userId from UserRating");
}
}
Я сконфигурировал упорство следующим образом:
@Configuration
@ComponentScan({ "com.estartup" })
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement
@EnableScheduling
public class PersistenceConfig {
@Autowired
Environment env;
@Scheduled(fixedRate = 5000)
public void run() {
userRatingManager().updateAllUsers();
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(env.getProperty("connection.url"), env.getProperty("connection.username"), env.getProperty("connection.password"));
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
return driverManagerDataSource;
}
public PersistenceConfig() {
super();
}
@Bean
public UserRatingUpdate userRatingUpdate() {
return new UserRatingUpdate();
}
@Bean
public UserRatingManager userRatingManager() {
return new DefaultUserRatingManager();
}
@Bean
public LocalSessionFactoryBean runnableSessionFactory() {
LocalSessionFactoryBean factoryBean = null;
try {
factoryBean = createBaseSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
return factoryBean;
}
private LocalSessionFactoryBean createBaseSessionFactory() throws IOException {
LocalSessionFactoryBean factoryBean;
factoryBean = new LocalSessionFactoryBean();
Properties pp = new Properties();
pp.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
pp.setProperty("hibernate.max_fetch_depth", "3");
pp.setProperty("hibernate.show_sql", "false");
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[] { "com.estartup.*" });
factoryBean.setHibernateProperties(pp);
factoryBean.afterPropertiesSet();
return factoryBean;
}
@Bean(name = "txName")
public HibernateTransactionManager runnableTransactionManager() {
HibernateTransactionManager htm = new HibernateTransactionManager(runnableSessionFactory().getObject());
return htm;
}
}
Однако, когда я добираюсь до:
Query q1 = getSession().createQuery("Select userId from UserRating");
в приведенном выше HibernateUserRatingDAO
Я получаю исключение:
org.hibernate.HibernateException: createQuery is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)
at com.sun.proxy.$Proxy63.createQuery(Unknown Source)
at com.estartup.dao.impl.HibernateUserRatingDAO.getAllUserIds(HibernateUserRatingDAO.java:36)
Как настроить включение запланированных задач в транзакции?
Редакция:
Вот код для BaseDAO
@Repository
public class BaseDAO<T, ID extends Serializable> extends GenericDAOImpl<T, ID> {
private static final Logger logger = LoggerFactory.getLogger(BaseDAO.class);
@Autowired
@Override
public void setSessionFactory(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
public void setTopAndForUpdate(int top, Query query){
query.setLockOptions(LockOptions.UPGRADE);
query.setFirstResult(0);
query.setMaxResults(top);
}
EDITED
Включение транзакции Spring распечатывает следующий журнал:
DEBUG [pool-1-thread-1] org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'updateAllUsers' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'txName'