如何关闭在 WildFly 上正确定义为 DataSource 的嵌入式 Derby
How to shutdown embedded Derby which is defined as a DataSource properly on WildFly
当我在 WildFly 上正常定义 Derby DataSource 时,db.lck 文件未被删除,这表明每次关闭 WildFly 时数据库都没有正确关闭。因为嵌入式 Derby 需要一个特殊的关闭过程,该过程正在获取与 JDBC URL 的新连接,该连接以“;shutdown=true”字符串结尾。
所以,我需要类似关闭挂钩的东西来执行关闭过程。我发现老JBoss有办法实现:
https://developer.jboss.org/wiki/SetUpADerbyDatasource
http://grepcode.com/file/repository.jboss.org/nexus/content/repositories/releases/org.jboss.jbossas/jboss-as-varia/6.0.0.Final/org/jboss/jdbc/DerbyDatabase.java
但我不知道如何在最近的 WildFly 上应用它,因为它的数据源定义中似乎不再允许 "mbean" 和 "depends" 元素,而且我找不到它相当于最近的 WildFly。
我觉得"connection-listener-class"数据源定义的变量很重要,不失为一种实现方式。我还没有尝试过,但它看起来有点复杂,我不确定它是否按预期工作。
那么,有没有办法定义一个 shutdown-hook 来使用最近的 WildFly 执行 Derby 的关闭过程?
编辑:
我发布了将 Apache Derby 安装到 WildFly 的说明,其中包括我的解决方案。
http://www.nailedtothex.org/roller/kyle/entry/installing-apache-derby-to-wildfly
connection-listener-class 如我所料。我注册了一个侦听器 class 然后 Derby 在 WildFly 每次关闭时正确地开始关闭。
但我应该记住一件事 - test-connection-in-pool
不会触发连接监听器-class。如果我只是启动 WildFly,然后执行 test-connection-in-pool
到 Derby 的数据源,然后关闭 WildFly,则永远不会调用侦听器并且 db.lck 将保持未删除状态。所以,这可能不是一个理想的解决方案。更直接的 shutdown-hook 之类的东西会更好。
我所做的如下:
- 将包含 ConnectionListener 实现和 module.xml 的 jar derby.jar 放入
$WILDFLY_HOME/modules/org/apache/derby/main
- 注册JDBC Derby 驱动程序(以下命令用于jboss-cli)
/subsystem=datasources/jdbc-driver=derby:add(driver-name=derby, driver-module-name=org.apache.derby, driver-class-name=org.apache.derby.jdbc.EmbeddedDriver)
- 注册数据源
data-source add --name=DerbyDS --driver-name=derby --connection-url=jdbc:derby:/Users/kyle/tmp/derbytest --jndi-name=java:jboss/jdbc/DerbyDS --user-name=sa --password=sa
- 配置连接监听器-class
/subsystem=datasources/data-source=DerbyDS:write-attribute(name=connection-listener-class, value=org.nailedtothex.derby.DerbyShutdownConnectionListener)
- 配置连接监听器-属性
/subsystem=datasources/data-source=DerbyDS:write-attribute(name=connection-listener-property,value={"url"=>"jdbc:derby:/Users/kyle/tmp/derbytest"}
module.xml
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.apache.derby">
<resources>
<resource-root path="derby.jar"/>
<resource-root path="derby-shutdown-hook-1.0-SNAPSHOT.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
<module name="org.jboss.ironjacamar.jdbcadapters"/>
</dependencies>
</module>
DerbyShutdownConnectionListener.java
Please refer GitHub for whole project contains pom.xml
import org.jboss.jca.adapters.jdbc.spi.listener.ConnectionListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DerbyShutdownConnectionListener implements ConnectionListener {
private static final Logger log = Logger.getLogger(DerbyShutdownConnectionListener.class.getName());
private static final String DEFAULT_URL = "jdbc:derby:";
private static final String SHUTDOWN_SUFFIX = ";shutdown=true";
private String url;
private String urlForShutdown;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
synchronized public void initialize(final ClassLoader classLoader) throws SQLException {
urlForShutdown = createUrlForShutdown();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
log.log(Level.INFO, "Shutdown derby. URL to use: {0}", urlForShutdown);
shutdown(urlForShutdown);
}
});
log.log(Level.INFO, "Derby shutdown hook added. URL to use: {0}", urlForShutdown);
}
private String createUrlForShutdown() {
return (url == null ? DEFAULT_URL : url) + SHUTDOWN_SUFFIX;
}
private void shutdown(String url) {
Connection cn = null;
try {
cn = DriverManager.getConnection(url);
} catch (SQLException e) {
if ("08006".equals(e.getSQLState()) || "XJ015".equals(e.getSQLState())) {
log.log(Level.INFO, "Derby shutdown succeeded. SQLState={0}", e.getSQLState());
return;
}
log.log(Level.SEVERE, "Derby shutdown failed", e);
} finally {
if (cn != null) {
try {
cn.close();
} catch (Exception e) {
}
}
}
}
@Override
public void activated(Connection connection) throws SQLException {
}
@Override
public void passivated(Connection connection) throws SQLException {
}
}
我找到了更好的 MBean 解决方案。它只是在每次 WildFly 关闭时执行关闭程序。
只需克隆 this repository 并构建一个 jar,将其放入 $WILDFLY_HOME/standalone/deployments
。项目中有各种文件,所以将所有文件都粘贴到这里很烦人。
对 org.jboss.ironjacamar.jdbcadapters、connection-listener-class 和 connection-listener-属性 的依赖是不必要的,所以现在 $WILDFLY_HOME/modules/org/apache/derby/main/module.xml
可以简化如下:
module.xml
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.apache.derby">
<resources>
<resource-root path="derby.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
当我在 WildFly 上正常定义 Derby DataSource 时,db.lck 文件未被删除,这表明每次关闭 WildFly 时数据库都没有正确关闭。因为嵌入式 Derby 需要一个特殊的关闭过程,该过程正在获取与 JDBC URL 的新连接,该连接以“;shutdown=true”字符串结尾。
所以,我需要类似关闭挂钩的东西来执行关闭过程。我发现老JBoss有办法实现:
https://developer.jboss.org/wiki/SetUpADerbyDatasource http://grepcode.com/file/repository.jboss.org/nexus/content/repositories/releases/org.jboss.jbossas/jboss-as-varia/6.0.0.Final/org/jboss/jdbc/DerbyDatabase.java
但我不知道如何在最近的 WildFly 上应用它,因为它的数据源定义中似乎不再允许 "mbean" 和 "depends" 元素,而且我找不到它相当于最近的 WildFly。
我觉得"connection-listener-class"数据源定义的变量很重要,不失为一种实现方式。我还没有尝试过,但它看起来有点复杂,我不确定它是否按预期工作。
那么,有没有办法定义一个 shutdown-hook 来使用最近的 WildFly 执行 Derby 的关闭过程?
编辑:
我发布了将 Apache Derby 安装到 WildFly 的说明,其中包括我的解决方案。 http://www.nailedtothex.org/roller/kyle/entry/installing-apache-derby-to-wildfly
connection-listener-class 如我所料。我注册了一个侦听器 class 然后 Derby 在 WildFly 每次关闭时正确地开始关闭。
但我应该记住一件事 - test-connection-in-pool
不会触发连接监听器-class。如果我只是启动 WildFly,然后执行 test-connection-in-pool
到 Derby 的数据源,然后关闭 WildFly,则永远不会调用侦听器并且 db.lck 将保持未删除状态。所以,这可能不是一个理想的解决方案。更直接的 shutdown-hook 之类的东西会更好。
我所做的如下:
- 将包含 ConnectionListener 实现和 module.xml 的 jar derby.jar 放入
$WILDFLY_HOME/modules/org/apache/derby/main
- 注册JDBC Derby 驱动程序(以下命令用于jboss-cli)
/subsystem=datasources/jdbc-driver=derby:add(driver-name=derby, driver-module-name=org.apache.derby, driver-class-name=org.apache.derby.jdbc.EmbeddedDriver)
- 注册数据源
data-source add --name=DerbyDS --driver-name=derby --connection-url=jdbc:derby:/Users/kyle/tmp/derbytest --jndi-name=java:jboss/jdbc/DerbyDS --user-name=sa --password=sa
- 配置连接监听器-class
/subsystem=datasources/data-source=DerbyDS:write-attribute(name=connection-listener-class, value=org.nailedtothex.derby.DerbyShutdownConnectionListener)
- 配置连接监听器-属性
/subsystem=datasources/data-source=DerbyDS:write-attribute(name=connection-listener-property,value={"url"=>"jdbc:derby:/Users/kyle/tmp/derbytest"}
module.xml
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.apache.derby">
<resources>
<resource-root path="derby.jar"/>
<resource-root path="derby-shutdown-hook-1.0-SNAPSHOT.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
<module name="org.jboss.ironjacamar.jdbcadapters"/>
</dependencies>
</module>
DerbyShutdownConnectionListener.java
Please refer GitHub for whole project contains pom.xml
import org.jboss.jca.adapters.jdbc.spi.listener.ConnectionListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DerbyShutdownConnectionListener implements ConnectionListener {
private static final Logger log = Logger.getLogger(DerbyShutdownConnectionListener.class.getName());
private static final String DEFAULT_URL = "jdbc:derby:";
private static final String SHUTDOWN_SUFFIX = ";shutdown=true";
private String url;
private String urlForShutdown;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
synchronized public void initialize(final ClassLoader classLoader) throws SQLException {
urlForShutdown = createUrlForShutdown();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
log.log(Level.INFO, "Shutdown derby. URL to use: {0}", urlForShutdown);
shutdown(urlForShutdown);
}
});
log.log(Level.INFO, "Derby shutdown hook added. URL to use: {0}", urlForShutdown);
}
private String createUrlForShutdown() {
return (url == null ? DEFAULT_URL : url) + SHUTDOWN_SUFFIX;
}
private void shutdown(String url) {
Connection cn = null;
try {
cn = DriverManager.getConnection(url);
} catch (SQLException e) {
if ("08006".equals(e.getSQLState()) || "XJ015".equals(e.getSQLState())) {
log.log(Level.INFO, "Derby shutdown succeeded. SQLState={0}", e.getSQLState());
return;
}
log.log(Level.SEVERE, "Derby shutdown failed", e);
} finally {
if (cn != null) {
try {
cn.close();
} catch (Exception e) {
}
}
}
}
@Override
public void activated(Connection connection) throws SQLException {
}
@Override
public void passivated(Connection connection) throws SQLException {
}
}
我找到了更好的 MBean 解决方案。它只是在每次 WildFly 关闭时执行关闭程序。
只需克隆 this repository 并构建一个 jar,将其放入 $WILDFLY_HOME/standalone/deployments
。项目中有各种文件,所以将所有文件都粘贴到这里很烦人。
对 org.jboss.ironjacamar.jdbcadapters、connection-listener-class 和 connection-listener-属性 的依赖是不必要的,所以现在 $WILDFLY_HOME/modules/org/apache/derby/main/module.xml
可以简化如下:
module.xml
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.apache.derby">
<resources>
<resource-root path="derby.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>