【问题标题】:Spring: Is using EntitiyManager in a @Component+@Transactional class thread safe?Spring:在@Component+@Transactional 类线程中使用EntityManager 是否安全?
【发布时间】:2018-11-01 20:54:05
【问题描述】:

我在 Spring 项目中使用 JPA(Hibernate)并问自己我的类“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 本身不是线程安全的。但是我正在参加的在线课程就是这样做的。也许春天有一些幕后魔法让它线程安全?

【问题讨论】:

  • 是的,它是线程安全的。 Spring 注入了一个代理,该代理委托给与当前事务/线程关联的 EM。见docs.spring.io/spring/docs/current/spring-framework-reference/…。这一切都在文档中进行了解释。
  • 感谢您的回答!但是在文档中,他们使用 EntityManagerFactory (线程安全)来获取 EntityManager 执行操作,然后将其关闭并结束 CRUD 方法。在我的示例中,我直接使用 EntityManager 而不是来自工厂。它仍然是线程安全的吗?
  • 多读第一句。我链接到的部分字面意思是:“注入的 JPA EntityManager 的行为类似于从应用程序服务器的 JNDI 环境中获取的 EntityManager,如 JPA 规范所定义的那样。它将所有调用委托给当前的事务性 EntityManager,如果有的话。否则,它会回退到每个操作新创建的 EntityManager,实际上使其使用线程安全。(强调我的)。该部分中的第 4 个示例 sn-p 显示了注入 EM 的用法。
  • 好的,谢谢!
  • 发布您的文字作为答案,它解决了我的问题

标签: java spring multithreading entitymanager


【解决方案1】:

是的,它是线程安全的。 Spring 注入了一个代理,该代理委托给与当前事务/线程关联的 EM。见the documentation,上面写着:

注入的 JPA EntityManager 的行为类似于从应用服务器的 JNDI 环境中获取的 EntityManager,如 JPA 规范所定义。它将所有调用委托给当前事务性 EntityManager(如果有)。否则,它会回退到每个操作新创建的 EntityManager,实际上使其使用线程安全

(强调我的)。

【讨论】:

    【解决方案2】:

    如果是线程安全的,你的意思是你不会有任何脏读不可重复读幻读的错误。不,这完全取决于您的事务隔离级别,该级别在您的 Hibernate 属性或每个 @Transactional 注释中配置。

    否则,两个不同的会话或线程(如果您使用@Async)是否可以同时访问相同的类方法并不重要,因为最终,它完全取决于您的隔离级别。这个blog 很好地说明了何时使用哪种隔离级别。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-29
      • 1970-01-01
      • 2015-05-16
      相关资源
      最近更新 更多