我正在尝试拆分批量数据库插入并使用工作线程在组中运行它们。但是,子线程内的sessionFactory.getCurrentSession()会产生:“java.util.concurrent.ExecutionException:org.hibernate.HibernateException:无法获取当前线程的事务同步会话”。如何设置在子线程中获取有效的当前会话?
@Configuration
@EnableTransactionManagement 公共类MockDbContext {
@Bean
@Autowired
public HibernateTransactionManager getHibernateTransactionManager( SessionFactory sessionFactory ){
HibernateTransactionManager manager = new HibernateTransactionManager();
manager.setSessionFactory( sessionFactory );
return manager;
}
@Autowired
@Bean
public static MyRepository getRepository( SessionFactory factory ) {
MyRepository repository = new MyRepository();
ReflectionTestUtils.setField( repository, "sessionFactory", factory );
return repository;
}
@Autowired
@Bean
public SessionFactory getSessionFactory( BasicDataSource dataSource, @Qualifier( "hibernateProperties" ) Properties hibernateProperties ) {
return new LocalSessionFactoryBuilder( dataSource )
.scanPackages( "com.hibernate.components" )
.addProperties( hibernateProperties )
.buildSessionFactory();
}
@Bean
public BasicDataSource getBasicDataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName( driverClassName );
dataSource.setUrl( url );
dataSource.setUsername( user );
dataSource.setPassword( pass );
return dataSource;
}
@Bean( name = "hibernateProperties" )
public Properties getHibernateProperties(){
Properties properties = new Properties();
properties.setProperty( "hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory" );
properties.setProperty( "hibernate.cache.use_query_cache", "true" );
properties.setProperty( "hibernate.cache.use_second_level_cache", "true" );
properties.setProperty( "hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect" );
properties.setProperty( "hibernate.hbm2ddl.auto", "create" );
properties.setProperty( "hibernate.show_sql", "true" );
return properties;
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public PersistenceExceptionTranslationPostProcessor getPersistenceExceptionTranslationPostProcessor(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
@Repository
public class MyRepository {
@Autowired
SessionFactory sessionFactory
protected Session getSession(){
return sessionFactory.getCurrentSession();
}
public Record findById( long id ){
return ( Record ) getSession().get( Record.class, id );
}
@Transactional
public Collection<Record> findByMultipleIds( Set<Long> ids ){
Collection<Record> records = new ArrayList<Record>();
List<Future<Record>> futures = new ArrayList<Future<Record>>();
ExecutorService pool = Executors.newFixedThreadPool( 10 );
for( int i = 0; i < ids.size(); ++i ){
futures.add( pool.submit( new MyCallable<Record>( ids.get( i ))));
}
for( Future<Record> future : futures ) {
records.add( future.get() );
}
return records;
}
private class MyCallable<Record> implements Callable<Record>{
private long id;
private MyCallable( long id ){
this.id = id;
}
@Override
public Record call(){
return findById( id );
}
}
}
@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,classes = MockDbContext.class) 公共类MyRepositoryTest {
@Rule
public ExpectedException exception = ExpectedException.none;
private Record expected;
@Autowired
private MyRepository repository;
public void testFindByIds() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
exception.expect( HibernateException.class );
exception.expectMessage( "Could not obtain transaction-synchronized Session for current thread" );
expected.findByMultipleIds( new HashSet<Long>( Arrays.asList( new long[]{1,2,3,4,5,6,7,8,9,10} )));
}
public void setUp(){
expected = new Record();
}
public void tearDown(){
expected = null;
}
}