【问题标题】:Binary File To SQL Database Apache Camel二进制文件到 SQL 数据库 Apache Camel
【发布时间】:2025-12-11 20:45:01
【问题描述】:

我需要一些关于使用 Camel 将二进制文件从文件夹加载到 MySQL 数据库的方法的指导。基本上,我想将我们 PBX 系统的语音日志存储到数据库中。包含语音日志的目录将是一个远程目录

我设计了一个原型,但我不确定这是否真的有效,它可以工作,但我对设计不满意。让我解释一下我在做什么。骆驼路线如下:

    <camelContext xmlns="http://camel.apache.org/schema/spring">
    <package>com.hia.camelone</package>
      <route>
            <from uri="file://c:/CTest/Inbox?noop=true&amp;recursive=true&amp;delay=3000"/>
            <to uri="bean://fileToSQL"/>
            <to uri="jdbc://timlogdb"/>

       </route>

</camelContext>

<bean id="timlogdb" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value=" com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/TimLog" />
    <property name="username" value="root" />
    <property name="password" value="blahblah" />
</bean>
<bean id="fileToSQL" class="com.hia.camelone.fileToSQL"/>

fileToSQL bean 的代码是:

public class fileToSQL {

public String toString(@Headers Map<String,Object> header, @Body Object body){
    StringBuilder sb = new StringBuilder();
    String filename =(String)header.get("CamelFileNameOnly");
    String escapedFileName = StringEscapeUtils.escapeJava(filename).replace("\'", "");
    String filePath = StringEscapeUtils.escapeJava((String)header.get("CamelFilePath"));

    sb.append("insert into FileLog ");
    sb.append("(FileName,FileData) values (");
    sb.append("'").append(escapedFileName).append("',").append("LOAD_FILE(\"").append(filePath).append("\")");
    sb.append(")");
    System.out.println(sb.toString());
    System.out.println(body);
    System.out.println(header.toString());
    return sb.toString();
}
}

好的简短解释我让文件组件使用文件然后我使用 MySQL LOAD_FILE() 函数构建一个 SQL 字符串来加载文件。

我对此的看法:

LOAD_FILE 函数仅适用于本地机器,因此此路由仅适用于本地机器上的文件。我可以使用文件生成器将文件从某个远程目录复制到本地目录,然后使用该路由。我的路线会是这样的:

<route>
            <from uri="file://c:/CTest/Inbox?noop=true&amp;recursive=true&amp;delay=3000"/>
            <to uri="file://c:/outbox"/>
            <to uri="bean://fileToSQL"/>
            <to uri="jdbc://timlogdb"/>

</route>

但是,由于我可以访问来自文件使用者的消息中的文件内容,理论上我应该能够访问字符串的正文/内容并构建不使用 LOAD_FILE() 函数的 SQL 命令.

我知道如何构建这样一个字符串的唯一方法是使用 JDBC 的预处理语句。如果我能以某种方式使用来自文件使用者的内容构建一个插入语句,这将是一等奖。

我可以在我的 fileToSQL bean 中创建一个准备好的语句并将它传递给我的 jdbc 组件吗? 或者如何在没有 LOAD_FILE() 函数的情况下构建 INSERT 语句?

由于我必须使用 LOAD_FILE() 函数,我现在必须同时满足 unix 和 windows 文件路径的要求。虽然这应该不难,但我只是不喜欢将特定于操作系统的代码放入我的应用程序的想法(感觉像是一种解决方法)。

这里的任何人都曾使用 Camel 将二进制文件上传到 MySQL 数据库,谁能就上述几点给我一些指导。虽然我可以解决这些问题,但我只是想确保我不会错过明显的做事方式。

我环顾四周,只发现人们主要使用文本文件。伙计们甚至请不要走我将文件存储在文件系统上并将其链接到数据库的路线。我们有一些非常具体的灾难恢复要求和法律要求,强制我将其存储在数据库中。

【问题讨论】:

  • 我对骆驼一无所知,但是将消息内容编码为 base64 字符串并插入数据库对您有用吗?然后你就可以正常插入了。
  • 这当然是一种可能性。我正在对此进行一些研究,似乎我确实可以访问文件的 byte[]。我找不到可靠示例的一件事是如何将此字节 [] 插入 mysql。大多数示例等都使用 JDBC 准备语句,虽然这很容易使用,但我不确定如何使用 Camel 执行此操作。另一种可能性是完全绕过 JDBC 组件,只在 bean 中使用普通的旧 jdbc。随着事情的发展,将进行试验并报告。

标签: mysql file-upload apache-camel


【解决方案1】:

是的,所以我设法找到了一种方法,这并不难。我本质上所做的是摆脱了路由中的 JDBC Camel 组件。然后我将数据源 bean 注入到我的 fileToSQL bean 中。然后我使用一个简单的准备好的语句将文件及其名称插入 MySQL。

一如既往,代码比我的英语更明确。

 <camelContext xmlns="http://camel.apache.org/schema/spring">
    <package>com.hia.camelone</package>

      <route>
            <from uri="file://c:/CTest/Inbox?noop=true&amp;recursive=true&amp;delay=3000"/>
            <to uri="bean://fileToSQL"/>
            <!--<to uri="jdbc://timlogdb"/>-->

       </route>

</camelContext>

<bean id="timlogdb" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value=" com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/TimLog" />
    <property name="username" value="root" />
    <property name="password" value="lalala" />
</bean>
<bean id="fileToSQL" class="com.hia.camelone.fileToSQL">
    <property name="dataSource" ref="timlogdb"/>
</bean>

如您所见,我将 timlogdb bean 注入到 fileToSQL bean 中。春天的摇滚!

这是我的 fileToSQL bean。

public class fileToSQL {
private DriverManagerDataSource dataSource;
private static final String SQL_INSERT="insert into FileLog(FileName,FileData)values(?,?)";
@Handler
public void toString(@Headers Map<String,Object> header,Exchange exchange){
    Connection conn = null;
    PreparedStatement stmt=null;
    String filename =StringEscapeUtils.escapeJava(((String)header.get("CamelFileNameOnly")).replace("\'", ""));

    try {
        conn= dataSource.getConnection();
        stmt =conn.prepareStatement(SQL_INSERT);
        stmt.setString(1, filename);
        byte[] filedata = exchange.getIn().getBody(byte[].class);
        stmt.setBytes(2,filedata );
        int s = stmt.executeUpdate();

    }
    catch (Exception e)
    {
        System.out.println(e.getMessage());
    }
    finally{
        try
        {
                if (stmt!=null)
                {
                    stmt.close();
                }
                if (conn!=null)
                {
                    conn.close();
                }
        }
        catch(SQLException e)
        {
            System.out.println(e.getMessage());
        }
    }


}

/**
 * @param dataSource the dataSource to set
 */
public void setDataSource(DriverManagerDataSource dataSource) {
    this.dataSource = dataSource;
}
}

骆驼队的人做得很好。 Camel 非常灵活,尤其是当您将它与 Spring 结合使用时。

真棒!

【讨论】:

  • 是的,我也喜欢在 bean 中使用 Spring 的 JdbcTemplate 进行 JDBC 访问。它给了我控制权。如果做大量的 SQL 工作,那么 MyBatis 也是一个很酷的框架。对于很少的 SQL 工作,请使用带有 Spring JdbcTemplate 的 Java Bean 或只是简单的 JDBC 代码。
  • 我已经更进一步,添加了一个池化数据源,允许我有效地重用我的 jdbc 连接。我还在 fileToSQL bean 中添加了一个线程池,允许我进行并发插入。我在 MySQL 数据库中每秒处理大约 9X 5mb 个文件。这令人印象深刻,因为它正在我的笔记本电脑上运行,甚至还没有在服务器上运行。不敢相信这是多么容易。
  • 您可以使用 DSL 中的 来实现开箱即用的并发性。多年前我写了一篇博文:davsclaus.blogspot.se/2009/05/…
  • 我确实在我的 DSL 中使用了 。我喜欢 Spring DSL 来完成大部分工作,然后转而使用 Java 来完成更专业的工作。标准组件及其 URI 之类的东西在 Spring DSL 中是有意义的,因为您可以更改配置而无需重新编译等。DSL 中的线程池也很酷,因为我可以很容易地微调线程和连接的数量以满足我的需要。使用 DSL 找到最佳位置是一种乐趣。