Spring: 在 @Component+@Transactional class 线程中使用 EntityManager 安全吗?
Spring: Is using EntitiyManager in a @Component+@Transactional class thread safe?
我在 Spring 项目中使用 JPA (Hibernate),并问自己我的 class '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 class:
@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 有一些幕后魔法使线程安全?
如果线程安全,你的意思是你不会有任何脏读、不可重复读或[=的错误17=]幻读。不,这完全取决于您的事务隔离级别,它在您的 Hibernate 属性或每个 @Transactional
注释中配置。
否则,如果两个不同的会话或线程(如果您正在使用 @Async
)可以同时访问相同的 class 方法,这并不重要,因为在最后,这将完全取决于您的隔离级别。 blog 给出了何时使用哪个隔离级别的好主意。
是的,它是线程安全的。 Spring 注入一个委托给与当前 transaction/thread 关联的 EM 的代理。请参阅 the documentation,其中表示:
The injected JPA EntityManager behaves like an EntityManager fetched from an application server’s JNDI environment, as defined by the JPA specification. It delegates all calls to the current transactional EntityManager, if any. Otherwise, it falls back to a newly created EntityManager per operation, in effect making its usage thread-safe.
(强调我的)。
我在 Spring 项目中使用 JPA (Hibernate),并问自己我的 class '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 class:
@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 有一些幕后魔法使线程安全?
如果线程安全,你的意思是你不会有任何脏读、不可重复读或[=的错误17=]幻读。不,这完全取决于您的事务隔离级别,它在您的 Hibernate 属性或每个 @Transactional
注释中配置。
否则,如果两个不同的会话或线程(如果您正在使用 @Async
)可以同时访问相同的 class 方法,这并不重要,因为在最后,这将完全取决于您的隔离级别。 blog 给出了何时使用哪个隔离级别的好主意。
是的,它是线程安全的。 Spring 注入一个委托给与当前 transaction/thread 关联的 EM 的代理。请参阅 the documentation,其中表示:
The injected JPA EntityManager behaves like an EntityManager fetched from an application server’s JNDI environment, as defined by the JPA specification. It delegates all calls to the current transactional EntityManager, if any. Otherwise, it falls back to a newly created EntityManager per operation, in effect making its usage thread-safe.
(强调我的)。