【问题标题】:Camel jdbc: How can I reset datasource if mysql connection gets closedCamel jdbc:如果mysql连接关闭,我如何重置数据源
【发布时间】:2014-07-10 10:43:05
【问题描述】:

我们开发了一个 Camel 捆绑包(部署在 Karaf 中),预计每 24 小时从 MySQL 拉取数据并将其推送到 S3。但是由于 MySQL 如果空闲 8 小时会在内部关闭连接,因此在下一次计划执行时它开始抛出错误。请从我们的代码中查看下面的 sn-ps。

属性:

MySqlDriver=com.mysql.jdbc.Driver
MySqlDatabaseURL=jdbc:mysql://x.x.x.x/dbname?autoReconnect=true
MySqlUsername=sm*****
MySqlPassword=*******

激活器:

public class Activator implements BundleActivator {

    public CamelContext context = null;

    public void start(BundleContext bundleContext) throws Exception {
        DataSource dataSource = UDMSUtils.createDataSource(UDMSUtils.getProperty(UDMSConstants.MYSQL_DATABASE_URL));

        SimpleRegistry simpleRegistry = new SimpleRegistry();
        simpleRegistry.put(UDMSConstants.UDMS_DATA_SOURCE, dataSource);

        context = new OsgiDefaultCamelContext(bundleContext, simpleRegistry);
        context.addRoutes(new CreativeRoutes());
        context.start();
    }

}

建筑数据源:

public static DataSource createDataSource(String connectURI) {
    BasicDataSource ds = new BasicDataSource();
    ds.setDriverClassName(getProperty(UDMSConstants.MYSQL_DRIVER));
    ds.setUsername(getProperty(UDMSConstants.MYSQL_USERNAME));
    ds.setPassword(getProperty(UDMSConstants.MYSQL_PASSWORD));
    ds.setUrl(connectURI);
    ds.setMaxWait(-1);  // Waits indefinately
    return ds;
}

路线:

from("timer://Timer?repeatCount=1").to("direct:record_count").end();

from("direct:record_count")
    .process(new Processor() {
        @Override
        public void process(Exchange exchange) throws Exception {
            exchange.getIn().setBody(query);
        }
    })    
    .routeId("record_count")
    .to("jdbc:" + UDMSConstants.UDMS_DATA_SOURCE)
    .process(new Processor() {
        @Override
        public void process(Exchange exchange) throws Exception {
            // ...
        }
    );

任何人都可以建议,需要在上面的代码中进行哪些更改,以便连接在我们需要的时间内保持活动状态。

请注意:我们无权更改mysql.properties,因此我们需要在代码中处理此问题。

【问题讨论】:

  • 你为什么不使用一个连接池,将借用自动测试(或任何它的调用)设置为 true。
  • 感谢 Steve (@vikingsteve),我在创建 dataSource 对象时添加了这一行:ds.setTestOnBorrow(true);,我现在正在测试它,我会在完成测试后将我的发现放入。

标签: java mysql jdbc apache-camel apache-karaf


【解决方案1】:

不久前我遇到了类似的问题。 VikingSteve 在他建议你做的事情上也很到位。由于我使用的是 OSGI 蓝图,所以我在 XML 中进行了所有配置,所以我着手解决它。

1) 在你的 pom 中添加一个 Apache Commons DBCP 依赖:

<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

2) 在你的骆驼路由/蓝图文件中声明连接池如下:

<bean id="MydataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" scope="singleton" >
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://DB-001:3306/Customer"/>
    <property name="username" value="sys_ETL"/>
    <property name="password" value="Blah"/>
    <property name="initialSize" value="4"/>
    <property name="maxActive" value="32"/>
    <property name="maxIdle" value="16"/>
    <property name="minIdle" value="8"/>
    <property name="timeBetweenEvictionRunsMillis" value="1800"/>
    <property name="minEvictableIdleTimeMillis" value="1800"/>
    <property name="testOnBorrow" value="true"/>
    <property name="testWhileIdle" value="true"/>
    <property name="testOnReturn" value="true"/>
    <property name="validationQuery" value="SELECT 1"/>
    <property name="maxWait"  value="1000"/>
    <property name="removeAbandoned" value="true"/>
    <property name="logAbandoned" value="true"/>
    <property name="removeAbandonedTimeout" value="30000"/>
</bean>

这一步将创建一个数据库连接池作为一个 bean,然后我可以在我的路由中使用它。这个 bean 的名字是 Mydatasource 我稍后会用到这个信息。还要注意我在配置中为连接池设置的属性。这些属性允许我的连接池增长和缩小,并且确保即使在空闲后连接也不会过时。

3)创建一个POJO来使用这个连接池:

public class AccountInformationToDatabase {


private BasicDataSource dataSource;
public BasicDataSource getDataSource() {
    return dataSource;
}
public void setDataSource(BasicDataSource dataSource) {
    this.dataSource = dataSource;
}
@Handler
public void PersistRecord
(
        @Body AccountRecordBindy msgBody
        , @Headers Map hdr
        , Exchange exch
) throws Exception
{

    Connection conn = null;
    PreparedStatement stmt=null;



    try 
    {


        conn= dataSource.getConnection();
        stmt =conn.prepareStatement("SOME INSERT STATEMENT");   

        stmt.setString(1,msgBody.getAccountNumber().trim());
        stmt.setString(2,msgBody.getRecordType().trim() );
        stmt.setString(3,msgBody.getSequenceNumber().trim());
        stmt.setString(4,msgBody.getTitle().trim());
        stmt.setString(5,msgBody.getCustomerType().trim());
        stmt.setString(6,msgBody.getName().trim());
        stmt.setString(7,msgBody.getAccountAddress1().trim());


        stmt.executeUpdate();        






    }
    catch (Exception e)
    {

        throw new Exception(e.getMessage());

    }

    finally
    {
        try
        {
                if (stmt!=null)
                {
                    stmt.close();
                    stmt= null;
                }
                if (conn!=null)
                {
                    conn.close();
                    conn= null;
                }
        }
        catch(SQLException e)
        {

            throw new Exception(e.getMessage());

        }

    }


}

}

此 POJO 有一个名为 datasource 的属性,其类型为 org.apache.commons.dbcp.BasicDataSource。我现在可以将Mydatasource bean 注入到这个 POJO 中,这样我的类就可以访问连接池了。

4)将POJO转为bean并注入连接池:

<bean id="AccountPersist"   class="AccountInformationToDatabase">
    <property name="dataSource" ref="MydataSource"/>
</bean>

如果您正在处理文本文件并希望使用并发插入等,此技术是必须具备的。

【讨论】:

  • 感谢@Namphibian,仅在借用时添加测试,这给了我类似的问题。请查看堆栈跟踪:com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception: ** BEGIN NESTED EXCEPTION ** java.net.SocketException MESSAGE: Broken pipe ,我现在将设置您的 xml 中提到的所有属性并重新进行测试。谢谢
  • 添加给定属性后,我在间隔 12 到 13 小时后执行了两次 bundle,现在 bundle 正在从数据源连接池获取有效连接。
【解决方案2】:

使用其他更高级的 JDBC 连接池,例如 HikariCP。设置jdbc4ConnectionTestconnectionTestQuery 属性以测试连接是否仍然存在。来自关于connectionTestQuery 的文档:

这适用于不支持 JDBC4 Connection.isValid() API 的“旧版”数据库。这是将在池中为您提供连接之前执行的查询,以验证与数据库的连接是否仍然有效。它依赖于数据库,并且应该是一个几乎不需要数据库处理的查询(例如“VALUES 1”)

【讨论】:

    猜你喜欢
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 2020-10-28
    • 2015-01-26
    相关资源
    最近更新 更多