Spring: Безопасно ли использовать EntitiyManager в потоке класса @ Component + @ Transactional? - PullRequest
0 голосов
/ 01 ноября 2018

Я использую JPA (Hibernate) в проекте Spring и спрашиваю себя, является ли мой класс BooksHandler (который является DAO) потокобезопасным?

Код для моей конфигурации приложения:

@Configuration
@EnableTransactionManagement
public class AppConfig {

@Bean
public LocalContainerEntityManagerFactoryBean getEntityManagerFactory() {

    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setDataSource(getDataSource());
    emf.setPackagesToScan("jpa.models");
    JpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    emf.setJpaVendorAdapter(adapter);
    emf.setJpaProperties(getProperties());
    return emf;
}

@Bean
public DataSource getDataSource() {
    DriverManagerDataSource dtSrc = new DriverManagerDataSource();
    dtSrc.setDriverClassName("com.mysql.jdbc.Driver");
    dtSrc.setUrl("jdbc:mysql://localhost:3306/jpa_example");
    dtSrc.setUsername("dbuser1");
    dtSrc.setPassword("dbuser1");
    return dtSrc;
}
private Properties getProperties() {
    Properties p = new Properties();
    p.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
    p.setProperty("hibernate.hbm2ddl.auto", "create");
    p.setProperty("hibernate.show_sql", "true");
    return p;
}

//auto transaction management
@Bean
public PlatformTransactionManager getTransactionManager(EntityManagerFactory emf) {
    JpaTransactionManager manager = new JpaTransactionManager();
    manager.setEntityManagerFactory(emf);

    return manager;
}

//auto exception management
@Bean
public PersistenceExceptionTranslationPostProcessor getPostProcessor() {
    return new PersistenceExceptionTranslationPostProcessor();
}
}

Класс DAO:

@Component 
@Transactional 
public class BooksHandler {

@PersistenceContext
private EntityManager em;

public Book createBook(String title, String isbn, int year) {
    Book b = new Book();
    b.setIsbn(isbn);b.setTitle(title);b.setYear(year);
    em.persist(b);
    System.out.println("book created: "+b.getId());
    return b;
}

public Book getBook(int id) {
    return em.find(Book.class, id);
}
//other CRUD methods
}

Метод BooksHandler будет использоваться несколькими потоками, и я знаю, что сам EntityManager НЕ является потокобезопасным. Но онлайн-курс, который я посещаю, делает это таким образом. Может быть, к весне у сцены есть какая-то магия, чтобы сделать ее безопасной для ниток?

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Да, это потокобезопасно. Spring внедряет прокси, который делегирует EM, связанный с текущей транзакцией / потоком. См. документацию , в которой говорится:

Внедренный JPA EntityManager ведет себя как EntityManager, извлеченный из среды JNDI сервера приложений, как определено в спецификации JPA. Он делегирует все вызовы текущему транзакционному EntityManager, если таковые имеются. В противном случае он возвращается к вновь созданному EntityManager для каждой операции, фактически делая его использование потокобезопасным .

(выделено мое).

0 голосов
/ 02 ноября 2018

Если потокобезопасным, вы имеете в виду, что у вас не будет ошибок Грязное чтение , Неповторяемое чтение или Фантомное чтение . Нет, это полностью зависит от уровня изоляции транзакции, который настраивается в ваших свойствах Hibernate или в каждой аннотации @Transactional.

В противном случае, не имеет большого значения, могут ли два разных сеанса или потока (если вы используете @Async) одновременно обращаться к одним и тем же методам класса, поскольку в конечном итоге это будет зависеть только от вашего уровень изоляции. Этот блог дает хорошее представление о том, когда и какой уровень изоляции использовать.

...