yeg
2026-09-29 b78295e8da96c3e5e76befeef9582ce5273dbb74
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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 主数据源的回滚不会波及厂商库。
 *
 * <p>连接复用一条并在查询失败时作废,避免厂商服务端重启后长期持有失效连接;
 * 厂商库实测按固定 60 秒写库,取数频率远低于连接复用带来的收益门槛。
 *
 * <p>{@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> T unwrap(Class<T> 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);
    }
}