使用Hibernate + Spring + C3P0 +多线程打开连接

时间:2018-08-09 09:20:12

标签: spring oracle hibernate c3p0

我有下一个抽象配置类:

@Configuration
@ComponentScan("my.app")
@EnableTransactionManagement
public abstract class AbstractApplicationConfig {
protected HibernateTransactionManager newHibernateTransactionManager(final LocalSessionFactoryBean localSessionFactoryBean) {
    final HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
    hibernateTransactionManager.setSessionFactory(localSessionFactoryBean.getObject());
    return hibernateTransactionManager;
}

protected LocalSessionFactoryBean newLocalSessionFactoryBean(final DataSource dataSource, final String packagesToScan) {
    final LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
    localSessionFactoryBean.setPackagesToScan(packagesToScan);
    localSessionFactoryBean.setDataSource(dataSource);

    final Properties properties = new Properties();
    properties.setProperty("hibernate.dialect", env.getRequiredProperty("databasePlatform"));
    properties.setProperty("hibernate.show_sql", env.getRequiredProperty("showSql"));
    properties.setProperty("hibernate.jdbc.batch_size", 10);
    properties.setProperty("hibernate.order_inserts", true);
    properties.setProperty("hibernate.order_updates", true);
    properties.setProperty("hibernate.jdbc.batch_versioned_data", true);

    properties.setProperty("hibernate.c3p0.min_size", 10);
    properties.setProperty("hibernate.c3p0.max_size", 50);
    properties.setProperty("hibernate.c3p0.timeout","300");
    properties.setProperty("hibernate.c3p0.max_statements", 50);
    properties.setProperty("hibernate.c3p0.idle_test_period", "3000");

    localSessionFactoryBean.setHibernateProperties(properties);
    return localSessionFactoryBean;
}

protected DataSource newDataSource() {
    final ComboPooledDataSource dataSource = new ComboPooledDataSource();
    try {
        dataSource.setDriverClass(env.getRequiredProperty("dataSource.driverClassName"));
        dataSource.setJdbcUrl(env.getRequiredProperty("dataSource.url"));
        dataSource.setUser(env.getRequiredProperty("dataSource.username"));
        dataSource.setPassword(env.getRequiredProperty("dataSource.password"));
        dataSource.setPreferredTestQuery("SELECT 1 FROM DUAL");
        dataSource.setMaxPoolSize(Integer.valueOf(50));
        dataSource.setMinPoolSize(Integer.valueOf(10));
        dataSource.setMaxStatements(Integer.valueOf(50));
    } catch (final IllegalStateException e) {
        e.printStackTrace();
    } catch (final PropertyVetoException e) {
        e.printStackTrace();
    }
    return dataSource;
}
}

我正在这样使用它:

@Configuration
public class SchemaApplicationConfig extends AbstractApplicationConfig {

/** DATASOURCES **/

@Bean
public DataSource dsSchema() {
    final DataSource dataSource = newDataSource(DataSourcesNames.SCHEMA1);
    return dataSource;
}

/** SESIONFACTORIES **/

@Bean
public LocalSessionFactoryBean sfSchema() {
    final LocalSessionFactoryBean localSessionFactoryBean = newLocalSessionFactoryBean(dsSchema(), "es.miapp.schema");
    return localSessionFactoryBean;
}

/** TRANSACTIONMANAGERS **/

@Bean
public HibernateTransactionManager txSchema() {
    final HibernateTransactionManager hibernateTransactionManager = newHibernateTransactionManager(sfSchema());
    return hibernateTransactionManager;
}
}

在我的应用程序中,我运行带有多个线程的进程:

public static void main(String... args) {
    AbstractApplicationContext context =  new AnnotationConfigApplicationContext(SchemaApplicationConfig.class);
    MainProcess mainProcess = context.getBean(MainProcess.class)
    mainProcess.execute();
    context.close();
    System.out.println("ENDS");
}

@Service
@Scope("prototype")
public class MainProcessImpl implements MainProcess{

    @Autowired
    protected ApplicationContext applicationContext;

    public void execute() {
        final ExecutorService executorService = Executors.newFixedThreadPool(5);
        final List<Future<?>> futures = new ArrayList<Future<?>>();
        for (int i = 0; i < 5; i++) {
            final MyService runnable = (MyService) applicationContext.getBean(MyServiceBean.class);
            final Future<?> future = executorService.submit(runnable);
            futures.add(future);
        }

        for (final Future<?> future : futures) {
            try {
                future.get();
            } catch (final InterruptedException e) {
                e.printStackTrace();
            } catch (final ExecutionException e) {
                e.printStackTrace();
            }
        }

        executorService.shutdown();
        try {
            executorService.awaitTermination(2, TimeUnit.MINUTES);
        } catch (final InterruptedException e) {
            e.printStackTrace();
        }
    }
}

MyServiceBean看起来像这样:

@Service
@Scope("prototype")
public class MyServiceBean implements Runnable {

    @Autowired
    private MyDao myDao;

    @Override
    public void run() {
        // Do Stuff and create entity
        myDao.insert(entity);
    }
}

我的刀像这样:

@Repository
public class MyDaoImpl implements MyDao {

    @Autowired
    @Qualifier("sfSchema")
    private SessionFactory sessionFactory;

    @Override
    @Transactional("txSchema")
    public void insert(Entity entity) {
        sessionFactory.getCurrentSession().persist(entity);
        sessionFactory.getCurrentSession().flush();
    }
}

这里的问题是Hibernate不会关闭所有连接,并且在运行几次此过程之后,我得到了下一个错误:

Caused by: java.net.BindException: Address already in use: connect

如果我继续执行实例,有一段时间程序会挂起并尝试执行插入操作:

[09-08-2018] [11:15:43,961] [DEBUG] [TEST] checkoutStatement: com.mchange.v2.c3p0.stmt.GlobalMaxOnlyStatementCache stats -- total size: 18; checked out: 6; num connections: 6; num keys: 18
[09-08-2018] [11:15:43,961] [DEBUG] [TEST] insert into ENTITY... COMPLETE SQL
[09-08-2018] [11:15:43,961] [DEBUG] [TEST] Executing batch size: 1

在Oracle上进行检查,可以看到我的用户已经打开了46个连接,并且每次运行时它们都在不断增加...

想法?

0 个答案:

没有答案