Skip to content

Commit 94bd9e1

Browse files
committed
fixes mybatis/migration#1 Drivers loaded at runtime via driverClassLoader were not registered correctly.
1 parent 0f1cd79 commit 94bd9e1

File tree

2 files changed

+121
-7
lines changed

2 files changed

+121
-7
lines changed

src/main/java/org/apache/ibatis/datasource/unpooled/UnpooledDataSource.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717

1818
import java.io.PrintWriter;
1919
import java.sql.Connection;
20+
import java.sql.Driver;
2021
import java.sql.DriverManager;
22+
import java.sql.DriverPropertyInfo;
2123
import java.sql.SQLException;
24+
import java.util.Enumeration;
25+
import java.util.Map;
2226
import java.util.Properties;
27+
import java.util.concurrent.ConcurrentHashMap;
2328
import java.util.logging.Logger;
2429

2530
import javax.sql.DataSource;
@@ -30,7 +35,7 @@ public class UnpooledDataSource implements DataSource {
3035

3136
private ClassLoader driverClassLoader;
3237
private Properties driverProperties;
33-
private boolean driverInitialized;
38+
private static Map<String, Driver> driverCache = new ConcurrentHashMap<String, Driver>();
3439

3540
private String driver;
3641
private String url;
@@ -41,7 +46,11 @@ public class UnpooledDataSource implements DataSource {
4146
private Integer defaultTransactionIsolationLevel;
4247

4348
static {
44-
DriverManager.getDrivers();
49+
Enumeration<Driver> drivers = DriverManager.getDrivers();
50+
while (drivers.hasMoreElements()) {
51+
Driver driver = drivers.nextElement();
52+
driverCache.put(driver.getClass().getName(), driver);
53+
}
4554
}
4655

4756
public UnpooledDataSource() {
@@ -121,7 +130,6 @@ public String getDriver() {
121130

122131
public synchronized void setDriver(String driver) {
123132
this.driver = driver;
124-
driverInitialized = false;
125133
}
126134

127135
public String getUrl() {
@@ -183,14 +191,18 @@ private Connection doGetConnection(Properties properties) throws SQLException {
183191
}
184192

185193
private synchronized void initializeDriver() throws SQLException {
186-
if (!driverInitialized) {
187-
driverInitialized = true;
194+
if (!driverCache.containsKey(driver)) {
195+
Class<?> driverType;
188196
try {
189197
if (driverClassLoader != null) {
190-
Class.forName(driver, true, driverClassLoader);
198+
driverType = Class.forName(driver, true, driverClassLoader);
191199
} else {
192-
Resources.classForName(driver);
200+
driverType = Resources.classForName(driver);
193201
}
202+
// http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
203+
Driver driverInstance = (Driver)driverType.newInstance();
204+
DriverManager.registerDriver(new DriverProxy(driverInstance));
205+
driverCache.put(driver, driverInstance);
194206
} catch (Exception e) {
195207
throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
196208
}
@@ -206,6 +218,38 @@ private void configureConnection(Connection conn) throws SQLException {
206218
}
207219
}
208220

221+
private static class DriverProxy implements Driver {
222+
private Driver driver;
223+
224+
DriverProxy(Driver d) {
225+
this.driver = d;
226+
}
227+
228+
public boolean acceptsURL(String u) throws SQLException {
229+
return this.driver.acceptsURL(u);
230+
}
231+
232+
public Connection connect(String u, Properties p) throws SQLException {
233+
return this.driver.connect(u, p);
234+
}
235+
236+
public int getMajorVersion() {
237+
return this.driver.getMajorVersion();
238+
}
239+
240+
public int getMinorVersion() {
241+
return this.driver.getMinorVersion();
242+
}
243+
244+
public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
245+
return this.driver.getPropertyInfo(u, p);
246+
}
247+
248+
public boolean jdbcCompliant() {
249+
return this.driver.jdbcCompliant();
250+
}
251+
}
252+
209253
public <T> T unwrap(Class<T> iface) throws SQLException {
210254
throw new SQLException(getClass().getName() + " is not a wrapper.");
211255
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*-
2+
* Copyright 2009-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.datasource.unpooled;
17+
18+
import static org.junit.Assert.*;
19+
20+
import java.net.URL;
21+
import java.net.URLClassLoader;
22+
import java.sql.Driver;
23+
import java.sql.DriverManager;
24+
import java.util.Enumeration;
25+
26+
import org.junit.Ignore;
27+
import org.junit.Test;
28+
29+
public class UnpooledDataSourceTest {
30+
31+
@Test
32+
public void shouldNotRegisterTheSameDriverMultipleTimes() throws Exception {
33+
// https://code.google.com/p/mybatis/issues/detail?id=430
34+
UnpooledDataSource dataSource = null;
35+
dataSource = new UnpooledDataSource("org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:multipledrivers", "sa", "");
36+
dataSource.getConnection();
37+
int before = countRegisteredDrivers();
38+
dataSource = new UnpooledDataSource("org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:multipledrivers", "sa", "");
39+
dataSource.getConnection();
40+
assertEquals(before, countRegisteredDrivers());
41+
}
42+
43+
@Ignore("Requires MySQL server and a driver.")
44+
@Test
45+
public void shouldRegisterDynamicallyLoadedDriver() throws Exception {
46+
int before = countRegisteredDrivers();
47+
ClassLoader driverClassLoader = null;
48+
UnpooledDataSource dataSource = null;
49+
driverClassLoader = new URLClassLoader(new URL[] { new URL("jar:file:/PATH_TO/mysql-connector-java-5.1.25.jar!/") });
50+
dataSource = new UnpooledDataSource(driverClassLoader, "com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1/test", "root", "");
51+
dataSource.getConnection();
52+
assertEquals(before + 1, countRegisteredDrivers());
53+
driverClassLoader = new URLClassLoader(new URL[] { new URL("jar:file:/PATH_TO/mysql-connector-java-5.1.25.jar!/") });
54+
dataSource = new UnpooledDataSource(driverClassLoader, "com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1/test", "root", "");
55+
dataSource.getConnection();
56+
assertEquals(before + 1, countRegisteredDrivers());
57+
}
58+
59+
protected int countRegisteredDrivers() {
60+
Enumeration<Driver> drivers = DriverManager.getDrivers();
61+
int count = 0;
62+
while (drivers.hasMoreElements()) {
63+
Driver driver = drivers.nextElement();
64+
System.out.println(driver.getClass().getName());
65+
count++;
66+
}
67+
return count;
68+
}
69+
70+
}

0 commit comments

Comments
 (0)