无法在运行批量数据库操作的子线程中获取hibernate会话

时间:2015-08-15 07:02:53

标签: java multithreading hibernate session

我正在尝试拆分批量数据库插入并使用工作线程在组中运行它们。但是,子线程内的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;
}

}

0 个答案:

没有答案