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