package com.battery.device.neware; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Properties; import java.util.logging.Logger; import javax.sql.DataSource; /** * 由 DriverManager 直连厂商库的极简数据源:只被设备适配器使用,不注册进 Spring, * 因此不参与任何业务事务,Druid 主数据源的回滚不会波及厂商库。 * *

连接复用一条并在查询失败时作废,避免厂商服务端重启后长期持有失效连接; * 厂商库实测按固定 60 秒写库,取数频率远低于连接复用带来的收益门槛。 * *

{@link DataSource} 接口中与连接获取无关的 JDK 样板方法(日志写出器、登录超时、父日志器、 * {@code unwrap} / {@code isWrapperFor})只转发驱动对象,不承载业务语义,因此不单独加方法注释。 */ public final class SingleConnectionVendorDataSource implements DataSource { private final String url; private final Properties credentials; private Connection connection; public SingleConnectionVendorDataSource(String url, String user, String password) { if (url == null || url.isBlank()) throw new IllegalArgumentException("vendor jdbc url must not be blank"); this.url = url; this.credentials = new Properties(); this.credentials.setProperty("user", user == null ? "" : user); this.credentials.setProperty("password", password == null ? "" : password); } /** 返回复用的单条连接,必要时按登记凭据新建;厂商库只读,连接不做写事务。 */ @Override public synchronized Connection getConnection() throws SQLException { if (connection == null || connection.isClosed()) { connection = DriverManager.getConnection(url, credentials); } return connection; } /** 按给定账号临时新建一条连接,不复用也不替换已缓存的那条。 */ @Override public Connection getConnection(String username, String password) throws SQLException { return DriverManager.getConnection(url, username, password); } /** 作废当前连接,使下一次取数重新建立;用于查询失败后的自愈。 */ public synchronized void invalidate() { if (connection == null) return; try { connection.close(); } catch (SQLException ignored) { // 连接已失效,无需处理。 } finally { connection = null; } } @Override public PrintWriter getLogWriter() throws SQLException { return DriverManager.getLogWriter(); } @Override public void setLogWriter(PrintWriter out) throws SQLException { DriverManager.setLogWriter(out); } @Override public void setLoginTimeout(int seconds) throws SQLException { DriverManager.setLoginTimeout(seconds); } @Override public int getLoginTimeout() throws SQLException { return DriverManager.getLoginTimeout(); } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return Logger.getLogger("com.battery.device.neware"); } @Override public T unwrap(Class iface) throws SQLException { if (iface.isInstance(this)) return iface.cast(this); throw new SQLFeatureNotSupportedException("不支持解包为 " + iface); } @Override public boolean isWrapperFor(Class iface) { return iface.isInstance(this); } }