Java 为使用MySQL和SQLServer的项目创建uberjar

Java 为使用MySQL和SQLServer的项目创建uberjar,java,jdbc,jar,clojure,leiningen,Java,Jdbc,Jar,Clojure,Leiningen,我正试图在clojure中构建一个项目,从 Microsoft SQL Server数据库,并将其推送到MySQL数据库 使用leinrun可以很好地运行该项目,但是当我将其打包到 uberjar使用leiningen,并使用java-jar运行,失败原因如下: 线程“main”java.sql.SQLException中的异常: 找不到适合jdbc的驱动程序:sqlserver 只有在尝试同时使用MySQL数据库和 SQL Server数据库。如果我单独使用其中任何一个,jar文件 使用jav

我正试图在clojure中构建一个项目,从 Microsoft SQL Server数据库,并将其推送到MySQL数据库

使用leinrun可以很好地运行该项目,但是当我将其打包到 uberjar使用leiningen,并使用java-jar运行,失败原因如下:

线程“main”java.sql.SQLException中的异常: 找不到适合jdbc的驱动程序:sqlserver

只有在尝试同时使用MySQL数据库和 SQL Server数据库。如果我单独使用其中任何一个,jar文件 使用java-jar运行良好

我的project.clj如下所示:

(defproject sqlserver-clojure "1.0.0-SNAPSHOT"
  :description "A minimal example of the MySQL/SQLServer conflict"
  :dependencies [[org.clojure/clojure "1.4.0"]
             [com.microsoft/sqljdbc4 "3.0"]
             [clojureql "1.0.4"]
             [mysql/mysql-connector-java "5.1.6"]]
  :main sqlserverclojure.core)

问题很可能是,在制作uber jar时,您没有复制驱动程序所需的某些文件(例如
.properties
或XML config),或者您正在覆盖两个JDBC驱动程序中存在的文件

覆盖的一个好例子是所有JDBC4驱动程序都具有的
META-INF/services/java.sql.Driver
文件。此文件包含jar中实现
java.sql.Driver
的所有类的列表,因此
java.sqlDriverManager
类可以使用自动加载所有驱动程序实现

如果使用多个JDBC驱动程序创建uber jar,则需要确保此文件包含所有这些文件的并集,或者应用程序需要使用
Class.forName(“”
)为每个所需的驱动程序显式加载所需的驱动程序,而不依赖于JDBC 4驱动程序的自动加载

还要验证创建uber jar的过程是否复制了所有资源,而不仅仅是
.class
文件


更好的是(在我看来),不要使用uber jar,而是将依赖的
.jar
文件保持在外部,并在应用程序的
META-INF/MANIFEST.MF
文件的
类路径中引用它们,这样可以为uber jar的正常工作节省大量的麻烦(或者验证它是否真的正常工作)。

添加此内容供我自己参考,因为我以前没有接触过Java,并且正在与Java互操作进行斗争


在命名空间中使用jdbc clojure函数调用。

Uber JAR是邪恶的;您可能不会复制
META-INF
中的某些资源或条目,或者更糟糕的是覆盖它们(例如
META-INF/services/java.sql.Driver
存在于所有具有不同内容的jdbc 4兼容驱动程序中),您可以始终回到“经典”在使用JDBC之前,在应用程序中的某个位置使用
Class.forName(“driver.Class.Name”)
加载JDBC驱动程序的方法。或者,您可以使用
DataSource
对象,而不是
DriverManager.getConnection()
@millimoose提到的
META-INF/services/java.sql.Driver
只是一个例子,驱动程序的加载仍然可能失败(即使使用经典方法或
数据源
),例如,因为其他所需资源不可用copied@MarkRotteveel有趣的是…jar包中确实有一个META-INF/services/java.sql.Driver,它只包含一个MySQL驱动程序的条目。在这里使用uberjar还有其他选择吗?你有什么建议吗?@markrotVeel它可能会失败,也可能不会,我不知道我相信在实践中,除了JDK利用这些信息的相对较少的特性之外,将任何东西置于
META-INF/
下都会有文件名冲突。除此之外,“其他东西可能会失败”给人的印象是FUD-spreading。很好的解释……但你知道这在未来版本的lein中是否可以纠正吗?(甚至可以修复吗?)@joefromct最简单的解决方案是不创建uber jar,而是在清单中引用所需的库。我不知道在将库合并到一个jar中时是否有解决所有这些问题的解决方案,因为我自己从来没有这样做过。从技术上讲,可以解决这些合并问题中的大多数问题,但可能存在以下情况:fig无法合并的同名文件。这个答案救了我的命。添加Class.forName()解决了这个问题。Class.forName()解决了这个问题顺便说一句,它不是线程安全的,如果出于性能原因,您通过多线程从不同的JDBC驱动程序创建连接,就不要这样做。@MertSerimer
Class.forName
加载驱动程序应该是线程安全的,但我知道有些JDBC驱动程序在加载时做了一些奇怪的事情,这可能会导致死锁。如果您运行into这样的问题,考虑向司机的维护者/供应商提交错误报告。@马克罗特韦尔:是的,我提到了你提到的死锁问题,所以它不是线程安全的,而是你所说的。嗯,再次谢谢你。
(. Class (forName "com.microsoft.sqlserver.jdbc.SQLServerDriver"))