Android Studio中JDBC监听器无法接收DatabaseChangeNotification求助
我来帮你梳理下几个常见的排查方向,都是移动端使用Oracle DCN容易踩的坑:
1. 检查数据库用户权限
Oracle的DCN功能要求用户必须拥有CHANGE NOTIFICATION权限,默认scott用户是没有这个权限的,这是最容易忽略的点。
- 解决方法:登录Oracle数据库,执行以下SQL授权:
GRANT CHANGE NOTIFICATION TO scott;
2. 确认JDBC连接配置与Android网络权限
网络权限
首先确保你的AndroidManifest.xml中添加了网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
明文网络访问(针对Android 8.0+)
如果你的数据库没有配置SSL,Android 8.0+默认会阻止明文TCP连接,需要配置网络安全规则:
- 在
res/xml目录下创建network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"/> </network-security-config>
- 在Manifest的
application标签中引用该配置:
<application ... android:networkSecurityConfig="@xml/network_security_config">
JDBC URL格式
确保你的连接URL是正确的Oracle Thin格式,比如:
return (OracleConnection)dr.connect("jdbc:oracle:thin:@//192.168.x.x:1521/XE");
替换成你的数据库实际IP和端口。
3. 调整DCN注册后的连接生命周期
你的代码中在注册DCN后立刻关闭了创建注册的conn,这可能导致JDBC驱动销毁监听通知的线程,从而收不到服务器推送的事件。
- 解决方法:把
conn.close()的代码移到取消DCN注册之后,修改后的核心结构大概是:
try { // 注册DCN、关联Statement等逻辑 ... // 插入数据、等待通知 synchronized(this) { // 插入数据的代码 ... this.wait(); } // 取消DCN注册 OracleConnection conn3 = connect(); conn3.unregisterDatabaseChangeNotification(dcr); conn3.close(); } catch(SQLException ex) { // 异常处理逻辑 } finally { // 最后关闭最初的连接 if(conn != null) { try { conn.close(); } catch(Exception innerex) { innerex.printStackTrace(); } } }
4. 确保DCN监听线程与UI线程不冲突
如果你的run()方法是在Android主线程调用的,this.wait()会直接导致ANR(应用无响应),而且DCN的回调线程无法正常唤醒主线程的等待状态。
- 解决方法:必须在子线程中执行
run()方法,比如用Thread实现:
// 按钮点击事件中调用示例 new Thread(new Runnable() { @Override public void run() { try { new DBChangeNotification().run(); } catch (SQLException e) { e.printStackTrace(); } } }).start();
5. 验证DCN注册的查询匹配逻辑
你注册DCN时用的查询是select * from dept where deptno='45',并且设置了DCN_QUERY_CHANGE_NOTIFICATION=true,这意味着只有当插入/修改的行满足deptno='45'时才会触发通知。你插入了deptno=45的行理论上应该触发,但可以尝试去掉查询条件(直接select * from dept)来测试是否能收到通知,排除查询条件匹配的问题。
6. 检查JDBC驱动兼容性
ojdbc6是针对Java SE 6开发的,在Android的ART虚拟机上可能存在部分API兼容问题,尤其是DCN用到的底层网络监听逻辑。可以尝试使用Oracle官方提供的Android兼容JDBC驱动,或者确认驱动版本与Oracle 11g的兼容性(11g推荐使用ojdbc6或ojdbc7)。
内容的提问来源于stack exchange,提问作者iphkez

