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

Java 无法在运行大容量数据库操作的子线程中获取hibernate会话,java,multithreading,hibernate,session,Java,Multithreading,Hibernate,Session,我正在尝试拆分一个大容量db插入,并使用工作线程分组运行它们。但是,子线程中的sessionFactory.getCurrentSession()会生成:“java.util.concurrent.ExecutionException:org.hibernate.HibernateException:无法获取当前线程的事务同步会话”。如何设置以在子线程中获取有效的当前会话 @Configuration @启用事务管理 公共类MockDbContext{ @Bean @Autowired pub

我正在尝试拆分一个大容量db插入,并使用工作线程分组运行它们。但是,子线程中的sessionFactory.getCurrentSession()会生成:“java.util.concurrent.ExecutionException:org.hibernate.HibernateException:无法获取当前线程的事务同步会话”。如何设置以在子线程中获取有效的当前会话

@Configuration
@启用事务管理 公共类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();
}
}

公共类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 );
    }   
}   
@Autowired
SessionFactory sessionFactory

protected Session getSession(){
    return sessionFactory.getCurrentSession();
}

public Record findById( long id ){
    return ( Record ) getSession().get( Record.class, id );
}

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 TemporarySession implements AutoCloseable{
    private Session session;
    protected TemporarySession(){
        create();
    }
    protected Session getSession(){
        return session;
    }
    protected void create(){
        session = sessionFactory.openSession();
    }
    protected void destroy(){
        session.flush();
        session.clear();
        session.close();
    }
    @Override
    public void close(){
        destroy();
    }
}

private class MyCallable<Record> implements Callable<Record>{
    private long id;
    private MyCallable( long id ){
        this.id = id;
    }
    @Override   
    public Record call(){
        try( TemporarySession tSession = new TemporarySession() ){
            return tSession.get( Record.class, id );
        }
    }   
}   
@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;
}
@规则
public ExpectedException exception=ExpectedException.none;
预期有私人记录;
@自动连线
私有MyRepository存储库;
public void testFindByIds()抛出NoSuchMethodException、SecurityException、IllegalAccessException、IllegalArgumentException、InvocationTargetException{
expect(hibernateeexception.class);
exception.expectMessage(“无法获取当前线程的事务同步会话”);
expected.findByMultipleIds(新的HashSet(Arrays.asList)(新的long[]{1,2,3,4,5,6,7,8,9,10}));
}
公共作废设置(){
预期=新记录();
}
公共无效拆卸(){
预期为空;
}

}

好吧,我最后添加了一个小类自动类,在子线程内创建新会话,并在子线程退出后立即关闭会话

公共类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 );
    }   
}   
@Autowired
SessionFactory sessionFactory

protected Session getSession(){
    return sessionFactory.getCurrentSession();
}

public Record findById( long id ){
    return ( Record ) getSession().get( Record.class, id );
}

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 TemporarySession implements AutoCloseable{
    private Session session;
    protected TemporarySession(){
        create();
    }
    protected Session getSession(){
        return session;
    }
    protected void create(){
        session = sessionFactory.openSession();
    }
    protected void destroy(){
        session.flush();
        session.clear();
        session.close();
    }
    @Override
    public void close(){
        destroy();
    }
}

private class MyCallable<Record> implements Callable<Record>{
    private long id;
    private MyCallable( long id ){
        this.id = id;
    }
    @Override   
    public Record call(){
        try( TemporarySession tSession = new TemporarySession() ){
            return tSession.get( Record.class, id );
        }
    }   
}   
@Autowired
会话工厂会话工厂
受保护会话getSession(){
返回sessionFactory.getCurrentSession();
}
公共记录findById(长id){
return(Record)getSession().get(Record.class,id);
}
公共集合FindByMultipleId(集合ID){
集合记录=新的ArrayList();
列表期货=新的ArrayList();
ExecutorService池=Executors.newFixedThreadPool(10);
对于(int i=0;i

}

一个事务不能由多个线程共享。每个线程需要启动并提交自己的事务(通过调用事务bean方法)。添加到JB Nizet上面所说的内容。如果您正在进行批处理,通常建议使用,否则您可能会遇到内存问题,因为Hibernate将在一级缓存中保留您查询的每个对象的副本(我假设批处理=处理大量记录)。谢谢你们,伙计们。我昨晚发现hibernate为每个线程的事务维护单独的会话。虽然主线程内事务的hibernate会话可以通过getCurrentSession简单地获得,但对于任何其他子线程都不能这样说
@Autowired
SessionFactory sessionFactory

protected Session getSession(){
    return sessionFactory.getCurrentSession();
}

public Record findById( long id ){
    return ( Record ) getSession().get( Record.class, id );
}

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 TemporarySession implements AutoCloseable{
    private Session session;
    protected TemporarySession(){
        create();
    }
    protected Session getSession(){
        return session;
    }
    protected void create(){
        session = sessionFactory.openSession();
    }
    protected void destroy(){
        session.flush();
        session.clear();
        session.close();
    }
    @Override
    public void close(){
        destroy();
    }
}

private class MyCallable<Record> implements Callable<Record>{
    private long id;
    private MyCallable( long id ){
        this.id = id;
    }
    @Override   
    public Record call(){
        try( TemporarySession tSession = new TemporarySession() ){
            return tSession.get( Record.class, id );
        }
    }   
}