我正在使用计划任务更新我的数据库,如下所示:
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'
答案 0 :(得分:4)
在这种情况下发生的事情是,由于您在配置中使用userRatingManager()
(实际调度的方法存在),Spring为处理UserRatingUpdate
的事务管理而创建的代理不是被使用。
我建议你做以下事情:
public interface WhateverService {
void executeScheduled();
}
@Service
public class WhateverServiceImpl {
private final UserRatingManager userRatingManager;
@Autowired
public WhateverServiceImpl(UserRatingManager userRatingManager) {
this.userRatingManager = userRatingManager;
}
@Scheduled(fixedRate = 5000)
public void executeScheduled() {
userRatingManager.updateAllUsers()
}
}
还要将您的事务管理器配置代码更改为:
@Bean(name = "txName")
@Autowired
public HibernateTransactionManager runnableTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sessionFactory);
return htm;
}
并从factoryBean.afterPropertiesSet();
createBaseSessionFactory
答案 1 :(得分:3)
正如我已经提到的,我使用了您的代码并创建了一个适合我的small sample。根据使用的类来判断,我假设您正在使用Hibernate Generic DAO Framework。它是一个独立的示例,main()
类是Main。运行它可以在日志中看到与事务相关的DEBUG消息,这些消息显示启动和提交事务的时间。您可以比较我的设置,使用的罐子版本以及是否有任何突出的东西。
另外,正如我已经建议的那样,您可能希望查看日志以查看是否正在使用正确的事务行为,并将其与我的示例创建的日志进行比较。
答案 2 :(得分:2)
我尝试复制您的问题,因此我将其集成到GitHub上的Hibernate示例中:
您可以运行我的CompanySchedulerTest并看到它正常运行,这就是我运行它所做的:
我确保应用程序上下文知道我们的调度程序
<task:annotation-driven/>
调度程序在其自己的bean中定义:
@Service
public class CompanyScheduler implements DisposableBean {
private static final Logger LOG = LoggerFactory.getLogger(CompanyScheduler.class);
@Autowired
private CompanyManager companyManager;
private volatile boolean enabled = true;
@Override
public void destroy() throws Exception {
enabled = false;
}
@Scheduled(fixedRate = 100)
public void run() {
if (enabled) {
LOG.info("Run scheduler");
companyManager.updateAllUsers();
}
}
}
我的JPA / Hibernate配置在applicationContext-test.xml中,根据Spring框架指示为JPA配置它们,所以你可能也需要仔细检查你的Hibernate设置。