我有一个使用Java,mybatis和SQL Anywhere的应用程序。由于某些情况,我必须在运行时手动加载SQLA驱动程序jar。我使用此代码进行此操作:
public static URLClassLoader ucl;
public static Driver saDriver;
public static final void loadSqlAnywhere(SqlAnywhereVersions version)
{
if (saDriver == null)
{
try
{
File jarPath = "path\\to\\sajdbc4.jar";
URL jarUrl = new URL("jar:file:" + jarPath.getAbsolutePath() + "!/");
String driverClass = "sap.jdbc4.sqlanywhere.IDriver";
ucl = URLClassLoader.newInstance(new URL[]{ jarUrl });
saDriver = new DriverShim((Driver) Class.forName(driverClass, true, ucl).newInstance());
DriverManager.registerDriver(saDriver);
}
catch (Exception ex)
{
// Could not load SQL Anywhere driver
}
}
}
当应用程序正在运行时,可能会升级SQL Anywhere。因此,我需要完全卸载旧的驱动程序,让更新发生,然后使用最新的jar进行初始化。我试过了:
private static List<SqlSession> sessions = new ArrayList<>();
private static SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder();
public static final void unloadSqlAnywhere()
{
if (saDriver != null)
{
// Close out any existing sessions
for (SqlSession session : sessions)
{
session.close();
}
sessions.clear();
// Kill the session factory
sessionFactory = null;
try
{
DriverManager.deregisterDriver(saDriver);
saDriver = null;
ucl.close();
ucl = null;
}
catch (Exception ex)
{
// Failed to unregister SQL Anywhere driver
}
}
}
但是使用jprofiler,我可以看到DriverManager仍在引用sap.jdbc4.sqlanywhere.IDriver
,这导致SQL Anywhere升级终止了我的应用程序。
还有其他我可以做的事情以确保删除所有驱动程序引用吗?还是有更好的方法来解决这个问题?
[大多数JDBC驱动程序会自动自行注册,例如您以前只需要调用Class.forName()
来加载驱动程序类,然后它将自动注册它。
如今,您甚至不必再这样做,因为它们使用服务框架通过仅在类路径上进行自动注册,但是由于您的JDBC jar文件不在类路径上,因此此处不再适用。
由于还注册了驱动程序,因此它被注册了两次,注销时,只删除您创建的注册,而不是自动注册的注册。
要删除自动注册的实例,您必须枚举所有已注册的驱动程序以找到要注销的实例:
// Any Java version
for (Enumeration<Driver> e = DriverManager.getDrivers(); e.hasMoreElements(); ) {
Driver driver = e.nextElement();
if (driver.getClass().getName().equals("sap.jdbc4.sqlanywhere.IDriver"))
DriverManager.deregisterDriver(driver);
}
// Java 9+
Optional<Driver> driver = DriverManager.drivers()
.filter(d -> d.getClass().getName().equals("sap.jdbc4.sqlanywhere.IDriver"))
.findAny();
if (driver.isPresent())
DriverManager.deregisterDriver(driver.get());