动态ActiveRecordPlugin出现configName已经存在的问题

private JSONObject getLedger(int pageNumber, int pageSize) {

        DruidPlugin dp = new DruidPlugin("jdbc:sqlserver://127.0.0.1:1433;databasename=ADB", "sa", "123456");

        ActiveRecordPlugin ap = new ActiveRecordPlugin("getLedger", dp);
        ap.setDialect(new SqlServerDialect());
        ap.setDevMode(true);
        ap.setShowSql(true);

        try {
            // 与 jfinal web 环境唯一的不同是要手动调用一次相关插件的start()方法
            dp.start();
            ap.start();

            //region 通过上面简单的几行代码,即可立即开始使用
            Page<Record> recordPage = Db.use("getLedger").paginate(pageNumber, pageSize, "select * ", "from t_v1 order by FID");
            JSONObject jsonObject = new JSONObject();
            //此处将分页结果转成JSON是用SF.JSON,不能使用FASTJSON
            jsonObject.put("data", JFinalJson.getJson().setDatePattern("yyyy-MM-dd HH:mm:ss").toJson(recordPage.getList()));
            jsonObject.put("code", 0);
            jsonObject.put("msg", "");
            jsonObject.put("count", recordPage.getTotalRow());
            System.out.println(jsonObject.toString());

            //endregion

            return jsonObject;

        } finally {
            ap.stop();
            dp.stop();
        }

    }

使用这种方法,在调试过程中出现提示:configName已经存在,如何修改以上代码,避免在生产环境下出现这种错误?

评论区

JFinal

2019-10-28 17:03

在 new ActiveRecordPlugin 时指令一个 configName,这个变量值只能唯一

如果希望使用相同的 configName,那么需要先 arp.stop() 关闭前一个 configName 对应的 arp 对象

configName 本质上是为了支持多数据源的

farce

2019-10-28 17:45

我增加了try finally,应该能释放掉吧。或者我把名称改为唯一值(UUID?),这个只是多次被调用,调用时才连接数据并不再使用,或者 dp = null; 和 ap = null;一下,让JAVA自动回收?
场景是URL参数传递主连接数据表中查询到数据库名称,再连接查询到的数据库,使用完成后就不再使用。

JFinal

2019-10-28 19:01

@farce 需要调用 ActiveRecordPlugin 的 stop() 方法才能回收

farce

2019-10-29 09:37

stop()以后,会自动被回收吗?还是需要手工处理一下?

JFinal

2019-10-29 10:27

@farce ActiveRecordPlugin 自己占用的资源会被回收,其被传入的 DataSource 资源需要手动 stop()

farce

2019-10-29 12:35

如果以 try(...) {} 方式来写,会报以下错误:
Incompatible types.
Required: java.lang.AutoCloseable
Found: com.jfinal.plugin.druid.DruidPlugin

Incompatible types.
Required: java.lang.AutoCloseable
Found: com.jfinal.plugin.activerecord.ActiveRecordPlugin

不支持close()。

代码改成以下:
DruidPlugin dp = null;
ActiveRecordPlugin ap = null;
try {
dp = new DruidPlugin(...);
ap = new ActiveRecordPlugin("getLedger", dp);
dp.start();
ap.start();
...
return
} finally {
ap.stop();
dp.stop();
ap = null; <-- 此处IDEA提示多余,但不这样写,总感觉没有释放掉
dp = null;
System.gc();
}
以上使用JMeter测试,10线程1秒时长,循环两次,测试时debug重启,还是会出现 Config already exists,将ActiveRecordPlugin的name改成uuid方式,则不再报错,但总感觉好像没有彻底释放,还有其他的什么方法没?

JFinal

2019-10-29 13:22

@farce arp.stop()以后应该会被回收的,建议在 start() 、stop() 方法中设置断点,单步调试看看到底是什么原因出现的 Config already exists

farce

2019-10-29 14:43

以下是报错信息:
[ERROR]-[Thread: XNIO-1 task-2]-[com.jfinal.core.ActionHandler.handle()]: com.xxkd.index.IndexController.g() : /g?page=1&limit=10
java.lang.IllegalArgumentException: Config already exists: getLedger
at com.jfinal.plugin.activerecord.DbKit.addConfig(DbKit.java:63)
at com.jfinal.plugin.activerecord.ActiveRecordPlugin.start(ActiveRecordPlugin.java:227)
at com.xxkd.index.IndexController.getLedger(IndexController.java:54)
at com.xxkd.index.IndexController.g(IndexController.java:28)
at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.jfinal.aop.Invocation.invoke(Invocation.java:97)
at com.jfinal.core.ActionHandler.handle(ActionHandler.java:89)
at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:89)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.SessionRestoringHandler.handleRequest(SessionRestoringHandler.java:119)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
======
加上时间变量进行信息打印
线程一:
dp start==>2019-10-29 14:30:10|null
ap start before==>2019-10-29 14:30:10|getLedger
ap start after==>2019-10-29 14:30:10|getLedger
....
ap stop before==>2019-10-29 14:30:10|getLedger
ap stop after==>2019-10-29 14:30:10|getLedger
dp stop==>2019-10-29 14:30:10|null
线程二:
dp start==>2019-10-29 14:30:10|null
ap start before==>2019-10-29 14:30:10|getLedger
ap start after==>2019-10-29 14:30:10|getLedger
....
ap stop before==>2019-10-29 14:30:10|getLedger
ap stop after==>2019-10-29 14:30:10|getLedger
dp stop==>2019-10-29 14:30:10|null
跟踪下,我想应该是多个线程同时访问产生的问题,以上复制了两个线程,发现时间是一样的。
所以,用了uuid后,发现是多线同一时间访问。
======
但是,activerecord stop后还是能获取到ap.getConfig().getName()名称
现在是不清楚该被调用的函数中的ActiveRecordPlugin和DruidPlugin是否被释放

farce

2019-10-29 14:51

DbKit.getConfig(uuid).getName()
在stop前是可以获取到uuid的,stop后就为null了,应该可以认为被释放了吧

JFinal

2019-10-29 15:04

@farce stop() 以后, DbKit.getConfig(configName) 是获取不到被释放的那个 config 对象的

你通过 arp.getConfig().getName() 获取到的只是从 DbKit 中移除的,但并不在系统内产生作用的对象

JFinal

2019-10-29 15:04

以 DbKit.getConfig(configName) 为准

热门反馈

扫码入社