Я немного озадачен механизмом выбора для обновления в Spring 4 и Hibernate.Я хотел бы сериализовать доступ к записям заданий в базе данных mySQL, вызывая select-for-update и помечая задания в работе, устанавливая значение (например, здесь называемое «count»).
- НАЧАЛО
- ВЫБРАТЬ * ИЗ РАБОТЫ, ГДЕ СЧЕТ <1 ДЛЯ ОБНОВЛЕНИЯ;// только 1 строка в БД для анализа, предложение LIMIT понадобится позже </li>
- ОБНОВЛЕНИЕ ЗАДАНИЯ SET count = count + 1;
- COMMIT
В коде Java я хочусломаться, когда считать> 0 и принять следующую работу.В командной строке это работает нормально.Пока первая передача не завершена, другая транзакция ожидает завершения первой транзакции.После этого, 2-й выбор правильно доставляет счет 1 вместо 0 (вместо «0», который был значением до начала 2-го выбора).Нет, так хорошо.
В Hibernate и Spring код останавливается (правильно) и продолжается, как только блокируемый tx будет зафиксирован.Красиво и правильно.
К сожалению, результатом является не «1» (как ожидалось), а старое значение «0».
Что не так?Я ожидал того же поведения, что и в командной строке?
POM:
<springframework.version>4.2.3.RELEASE</springframework.version>
<mysql.connector.version>5.1.31</mysql.connector.version>
<hibernate.version>4.3.11.Final</hibernate.version>
Объект:
@Entity
@Table(name = TableNames.Job)
public class Job implements Serializable, DataModel {
private static final long serialVersionUID = -5552161667860673186L;
private Integer id;
private Integer count;
public Job() {
super();
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(unique = true, nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
Конфиг:
@Configuration
@EnableTransactionManagement
@EnableScheduling
@ComponentScan({ "blabla", "blabla"})
@PropertySource(value = { "classpath:application.properties" })
public class ContextConfiguration {
private static Logger LOG = LoggerFactory.getLogger(ContextConfiguration.class);
@Autowired
private Environment env;
@Bean
public DataSource dataSource() {
return new JndiDataSourceLookup().getDataSource("java:comp/env/jdbc/blabblabbla");
}
@Bean
public LocalSessionFactoryBean sessionFactory() {
LOG.debug("getSesionFactory !!!!! ******");
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "blabla" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
@Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties hibernateProperties() {
System.out.println("Hibernate properties gelesen !!!!! ******");
return new Properties() {
private static final long serialVersionUID = 2082799704578665372L;
{
setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
setProperty("hibernate.globally_quoted_identifiers", "true");
}
};
}
Тестовый код:
@Transactional
public void doTest() {
List<Job> jobs = session.createQuery("From " + tableName + " where id=1").setLockMode(tableName, LockMode.UPGRADE_NOWAIT).list();
if (jobs.size() == 1) {
Job job = jobs.get(0);
session.flush();
session.refresh(job);
session.flush();
System.out.println(job.getCount() + "->" + (job.getCount() + 1));
job.setCount(job.getCount() + 1);
session.update(job);
session.flush();
}
Имена таблиц (только для понимания)
public interface TableNames {
public static final String Job = "Job";
//Blabblablabla
}
Как вы можете видеть, я пытался убедиться в отсутствии проблем с кэшированием, сбрасываясумасшедший, но я не помогаю.Метод test () вызывается через службу таймера весны каждые 2 миллисекунды.Как только я вызываю команду select-for-update в командной строке, вывод останавливается и ждет, пока я не обновлю счетчик до «0» и не напишу «COMMIT» в командной строке.Но объект задания в java не обновился, это 1323432 или то, что когда-либо было раньше - несмотря на то, что он ожидает точно в позиции оператора выбора для обновления в коде java - как в командной строке.
Есть идеи, в чем проблема?
Спасибо всем !!