Jruby、JDBC、Netezza
不管怎样,我有一个像这样的java程序,它完全可以工作。
1 import java.sql.*;
2 import org.netezza.*;
class Conn {
public static void main (String args []) throws SQLException {
6 try{Class.forName ("org.netezza.Driver");
7 }
8 catch (ClassNotFoundException e) {
9 System.out.println("You made it to here");
10 e.printStackTrace();
11 }
12
13 Connection conn = DriverManager.getConnection("jdbc:netezza://server/dbname", "user", "pass");
14
15 Statement stmt = conn.createStatement();
16 ResultSet rset = stmt.executeQuery("SELECT 'foo'");
17 while (rset.next()){
18 System.out.println(rset.getString(1));
19 }
20 stmt.close();
21 conn.close();
22 }
23 }
然而,当我尝试遵循互联网上的每一个普通 JDBC + Jruby 教程时,我都会收到此代码中普遍存在的错误“NativeException:java.sql.SQLException:没有合适的驱动程序”。
1 require 'java'
2 require 'jruby'
3 require 'nzjdbc.jar'
4 #F = java.io.File
5 #class_loader = JRuby.runtime.jruby_class_loader
6 #class_loader.add_url(F.new('path').to_url)
7 #class_loader.add_url(F.new('nzjdbc.jar').to_url)
8
9 include_class "java.sql.DriverManager"
10 include_class "org.netezza.Driver"
11
12 p $CLASSPATH
13 p $LOAD_PATH
14
15 server = 'server'
16 databaseName = 'dbname'
17 user = 'user'
18 pass = 'pass'
19
20 p DRVRMAN = org.netezza.Driver.new
21
22 begin
23 #clazz = Java::JavaClass.for_name("org.netezza.Driver")
24 clazz = java.lang.Class.for_name("org.netezza.Driver", true, JRuby.runtime.jruby_class_loader)
25 #java.lang.Thread.currentThread.setContextClassLoader(JRuby.runtime.jruby_class_loader)
26 #java.sql.DriverManager.registerDriver(Java::OrgNetezza::Driver.new)
27 url = "jdbc:netezza://" + server + "/" + databaseName
28 p url
29 conn = DriverManager.getConnection(url, user, pass)
30 stmt = conn.create_statement
31 rs = stmt.execute_query("SELECT 2 + 2")
32
33 while rs.next
34 p [rs.get_int(1)]
35 end
36 ensure
37 rs.close rescue nil
38 stmt.close rescue nil
39 conn.close rescue nil
40 end
我已经尝试了所有我能找到的方法来解决这个问题,包括检查 activerecord-jdbc 和 dbi-jdbc 实现。这非常令人沮丧,我想除了类加载器、加载路径和类路径有问题之外,我真的不明白发生了什么。不管怎样,我希望有人能一步一步解释 DriverManager 如何在 Java 中注册驱动程序,以及为什么 java 代码完全成功,而 ruby 代码(看起来等效)却不能帮助我减轻这些错误。
(此外,任何“安装 X gem”在这种情况下都不起作用,因为必须克服大量官僚主义才能允许任何新内容进入该系统)
So anyways I have a java program like this and it totally works.
1 import java.sql.*;
2 import org.netezza.*;
class Conn {
public static void main (String args []) throws SQLException {
6 try{Class.forName ("org.netezza.Driver");
7 }
8 catch (ClassNotFoundException e) {
9 System.out.println("You made it to here");
10 e.printStackTrace();
11 }
12
13 Connection conn = DriverManager.getConnection("jdbc:netezza://server/dbname", "user", "pass");
14
15 Statement stmt = conn.createStatement();
16 ResultSet rset = stmt.executeQuery("SELECT 'foo'");
17 while (rset.next()){
18 System.out.println(rset.getString(1));
19 }
20 stmt.close();
21 conn.close();
22 }
23 }
However, when I attempt to follow what seems like every vanilla JDBC + Jruby tutorial on the internet I get the ubiquitous error "NativeException: java.sql.SQLException: No suitable driver" with this code.
1 require 'java'
2 require 'jruby'
3 require 'nzjdbc.jar'
4 #F = java.io.File
5 #class_loader = JRuby.runtime.jruby_class_loader
6 #class_loader.add_url(F.new('path').to_url)
7 #class_loader.add_url(F.new('nzjdbc.jar').to_url)
8
9 include_class "java.sql.DriverManager"
10 include_class "org.netezza.Driver"
11
12 p $CLASSPATH
13 p $LOAD_PATH
14
15 server = 'server'
16 databaseName = 'dbname'
17 user = 'user'
18 pass = 'pass'
19
20 p DRVRMAN = org.netezza.Driver.new
21
22 begin
23 #clazz = Java::JavaClass.for_name("org.netezza.Driver")
24 clazz = java.lang.Class.for_name("org.netezza.Driver", true, JRuby.runtime.jruby_class_loader)
25 #java.lang.Thread.currentThread.setContextClassLoader(JRuby.runtime.jruby_class_loader)
26 #java.sql.DriverManager.registerDriver(Java::OrgNetezza::Driver.new)
27 url = "jdbc:netezza://" + server + "/" + databaseName
28 p url
29 conn = DriverManager.getConnection(url, user, pass)
30 stmt = conn.create_statement
31 rs = stmt.execute_query("SELECT 2 + 2")
32
33 while rs.next
34 p [rs.get_int(1)]
35 end
36 ensure
37 rs.close rescue nil
38 stmt.close rescue nil
39 conn.close rescue nil
40 end
and I have tried what seems like everything I could find to fix this issue including checking out the activerecord-jdbc and dbi-jdbc implementations. Its very frustrating and I guess I don't really understand whats going on besides having an issue with teh classloader, load path and the Classpath. Anyways, I was hoping someone could explain step by step how the DriverManager registers drivers in Java and why the java code totally succeeds while the ruby code (which seems equivalent) does not as well as help me mitigate these errors.
(Also any "install X gem" won't work in this instance as a large deal of bureaucracy must be overcome for anything new to be allowed into this system)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当其他所有方法都因类路径问题而失败时,我发现将 jar 放在 $JRUBY_HOME/lib 中总是有效的。
When all else fails with classpath issues, I've found that putting jars in $JRUBY_HOME/lib always works.
我在使用 Apache CXF 时遇到过这种情况。我最喜欢的解决方案是
,100% 保证有效。在你的情况下,你可以编译/jar你的Conn类并从jruby调用它,就像
你的jar可以放在jruby/lib中一样。
PS:我看到你已经尝试了很多方法来使其发挥作用。
也许 Nick Sieger 可以提供一些有关这些类加载问题的见解。
I have run into this scenario with Apache CXF. My favorite solution is to
, which is 100% guaranteed to work. In your case, you can compile/jar your Conn class and call it from jruby like
Your jar can be placed in jruby/lib.
PS: I see you have tried numerous ways to make it work.
Probably Nick Sieger can provide some insight into these class loading issues.
虽然它没有解决使用 nzjdbc.jar 的具体问题,但我可以告诉您,您拥有的代码将与 postgresql.jar 一起使用,因此您的问题必须特定于驱动程序的某些怪癖。我不确定 netezza 想要做什么,但是对于 postgresql 驱动程序, org.postgresql.Driver 有一个静态初始化块,它只调用 javax.sql.DriverManager.registerDriver(new org.postgresql.Driver()),所以只需加载该类就足以注册驱动程序。
While it doesn't address the specific issue of using your nzjdbc.jar, I can tell you that the code you have will work with postgresql.jar, so your issue must be specific to some quirk of your driver. I'm not sure what netezza is trying to do, but with the postgresql driver, org.postgresql.Driver has a static initialization block that simply calls javax.sql.DriverManager.registerDriver(new org.postgresql.Driver()), so simply loading that class is enough to get the driver registered.