【发布时间】:2012-04-26 17:08:08
【问题描述】:
在JDBC中,我们主要使用Connection、Statement和ResultSet这三个接口来连接和执行DB中的语句。但是它们对应的对象稍后用于运行 createStatement()、executeQuery()、next() 等方法。哪个类实现了这些方法? 为什么它被称为连接对象而不是实现的类对象?
【问题讨论】:
在JDBC中,我们主要使用Connection、Statement和ResultSet这三个接口来连接和执行DB中的语句。但是它们对应的对象稍后用于运行 createStatement()、executeQuery()、next() 等方法。哪个类实现了这些方法? 为什么它被称为连接对象而不是实现的类对象?
【问题讨论】:
在 JDBC 中,您首先通过调用注册驱动程序
Class.forName('classname')
加载数据库类并将该类注册到DriverManager
当你说DriverManager.getConnection() - 它返回你java.sql.Connection(根据规范的合同)
哪个类实现了这些方法?
实际的实现由数据库供应商提供,例如甲骨文、MySQL。
为什么它被称为连接对象而不是实现类 对象?
因为你code to Interface and not implementation(良好的编码习惯)。
如果你愿意,你可以在供应商的 jar 中查找,然后找到哪个类实现了 Connection 而不是
Connection connection = DriverManager.getConnection()
你可以写
VendorConnectionImpl vendorConnection = (VendorConnectionImpl)DriverManager.getConnection()
上面的方法会起作用,但它会将您与特定的实现绑定在一起。
如果你想从 vendor1 移动到 vendor2 你不能这样做,首先你必须根据 vendor2 API 更改上面的代码,但是如果你使用第一种方法,你可以从 Vendor 移动到 Vendor 而无需更改你的代码。
【讨论】:
Class.forName“加载”驱动程序(如果您使用的是符合 JDBC 4 的驱动程序)
你实际上并没有这样做
Connection conn = new Connection();
你做了类似的事情
Connection conn = DriverManager.getConnection(
DB_PATH + "?user=" + USER_NAME + "&password=" + USER_PASS);
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(query);
但要直接回答您的问题,不,您不能实例化 Interface,您必须使用 implements Interface 的类或使用代理。
【讨论】:
Statement 接口的类都必须重写executeQuery() 方法(以及该接口的任何其他方法)。您使用哪一个取决于conn.createStatement() 的工作方式以及它实际返回的内容。
conn.getClass() 的实际类名,它会告诉您名称,但您真的不应该使用JDBC 旨在通过其接口工作的具体类.
您不能实例化接口类。您要么自己实现该接口,要么使用Proxy 创建所述接口的实例,将所有调用委托给提供的InvocationHandler。
【讨论】:
这些人正在回答你的问题,但我认为你不是从 cmets 那里得到的。
您需要通过创建自己的类来实际实现接口。因此,创建一个实现接口的类,包含正确的抽象方法,然后将您想要的任何内容添加到新类中的功能中。然后您将实例化该类以使用这些函数。
接口就像一个编程“合同”,它的存在是为了确保使用的任何扩展接口的类都满足某些功能,但是,您不能实例化接口本身以使用其方法,您可以继承/覆盖它们他们在你的新班级。覆盖新类中的抽象方法后,您可以编写任何您希望特定接口扩展类执行的操作。
http://www.javabeginner.com/learn-java/java-abstract-class-and-interface 和 http://www.javaworld.com/javaworld/javaqa/2001-04/03-qa-0420-abstract.html 将让您阅读这些主题。
【讨论】:
希望下面的解释会有所帮助。
问:驱动连接实现从何而来?以及Statement和ResultSet的实现?
Class.forName("com.mysql.jdbc.Driver").newInstance();
// String url="jdbc:mysql://localhost:3306/mydb?user=root&password=root";
Connection con = DriverManager.getConnection(url);
小提示:一旦 DriverManager 类被加载(初始化),驱动程序实现就会被加载。
以mysql-connector-java:5.1.36的源码为例
● 类 com.mysql.jdbc.Driver 扩展类 NonRegisteringDriver,其中有一个名为 connect() 的方法,它返回一个连接实例。
注意 NonRegisteringDriver 的 registeredDrivers 字段
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
...
public java.sql.Connection connect(String url, Properties info) throws SQLException {
● mysql驱动注册,驱动添加到registeredDrivers:
Class.forName("com.mysql.jdbc.Driver");
...
java.sql.DriverManager.registerDriver(new Driver()); // from com.mysql.jdbc.Driver
...
registeredDrivers.addIfAbsent(new DriverInfo(driver, da)); // mysql driver instance is added to registeredDrivers
从现在开始JDBC知道有一种JDBC实现,即mysql。
● 然后创建连接:
Connection con = DriverManager.getConnection(url);
● 关注DriverManager.getConnection的源码
注意注册司机
这里的connection implementation是由aDriver.driver.connect
for(DriverInfo aDriver : registeredDrivers) {
...
Connection con = aDriver.driver.connect(url, info);
...
}
● 既然已经找到了mysql的连接实现,那么Statement和ResultSet的实现也可以通过挖掘mysql-connector-java的源码找到: 5.1.36
Statement stmt = con.createStatement();
// String sql = "select * from user";
ResultSet rs=stmt.executeQuery(sql);
对于JDBC 4,DriverManager类加载时会自动从classpath中检测驱动实现:
DriverManager.java#l101
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
...
private static void loadInitialDrivers() {
...
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
...
}
文件 mysql-connector-java-5.1.36.jar!/META-INF/services/java.sql.Driver的内容:
com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver
【讨论】: