在JDBC中使用isWrapperFor和unwrap函数的正确方法是什么?

use*_*191 0 java jdbc

我想知道isWrapperFor在JDBC中验证和解包函数的正确方法.这里HIRAConnection使用标准Connection类.

HIRAConnection hiraCon1 = (HIRAConnection) ds.getConnection();
Connection conn = ds.getConnection();
if (hiraCon1 instanceof Wrapper) {
    // try to use java 6 unwrapping
    try {
        Wrapper w = conn;
        if (hiraCon1.isWrapperFor(Connection.class)) {
            hiraCon1 = conn.unwrap(HIRAConnection.class); 
            hiraCon1= hiraCon1.unwrap(HIRAConnection.class);
            hiraCon1= ds.unwrap(HIRAConnection.class);//returns SQLException   
        }
        if (hiraCon1.isWrapperFor(HIRAConnection.class)) {
            hiraCon1 = conn.unwrap(HIRAConnection.class);
            hiraCon1 = hiraCon1.unwrap(HIRAConnection.class);    
        }
        if (conn.isWrapperFor(com.hira.HIRAConnection.class)) {          
            hiraCon1 = conn.unwrap(com.hira.HIRAConnection.class);
        } 
        if (conn.isWrapperFor(Connection.class)) {          
            hiraCon1 = conn.unwrap(com.hira.HIRAConnection.class);
        } 
    } catch (Throwable t) {
        System.out.println("Failed to unwrap connection using java 6 facilities");
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*eel 5

正确的使用java.sql.Wrapper方法记录在其javadoc中.

用于isWrapperFor(Class<?> iface):

如果这实现了接口参数,或者直接或间接地作为对象的包装器,则返回true.否则返回false.如果这实现了接口然后返回true,否则如果这是一个包装器,则返回递归调用isWrapperFor包装对象的结果.如果这不实现接口并且不是包装器,则返回false.此方法应该作为低成本操作实现, unwrap以便调用者可以使用此方法来避免unwrap 可能失败的昂贵调用.如果此方法返回true unwrap ,则应使用相同的参数调用成功.

参数:
iface- 定义接口的类.
返回:
如果此实现接口或直接或间接包装执行该操作的对象,则返回 true.

并为unwrap(Class<T> iface):

返回实现给定接口的对象,以允许访问非标准方法或代理未公开的标准方法.如果接收器实现接口,则结果是接收器或接收器的代理.如果接收器是包装器并且包装对象实现接口,则结果是包装对象或包装对象的代理.否则返回在unwrap包装对象或该结果的代理上递归调用的结果.如果接收者不是包装器并且没有实现接口,则SQLException抛出a.

类型参数:
T- 此类对象建模的类的类型
参数:
iface- 定义结果必须实现的接口的类.
返回:
实现接口的对象.可以是实际实现对象的代理.
抛出:
SQLException- 如果找不到实现接口的对象

换句话说,wrapperFor如果包装器可以解包到接口,您可以首先检查使用,然后您可以使用unwrap真正解包到该接口.请注意,规范仅提到了对接口进行解包的支持,因此实际上可能无法解开具体类.

这是否有效,取决于所使用的驱动程序(并非所有驱动程序都支持解包,或者它们没有任何有用的解包),如果您使用的是连接池库,那么完全有可能它不允许您解包到 - 例如 - 底层连接,因为这样做可以允许您规避或破坏连接池的某些限制和要求.

所以使用包装的正确方法是:

Connection conn = ds.getConnection();
if (conn.isWrapperFor(HiraConnection.class)) {
    HIRAConnection hiraCon1 = conn.unwrap(HiraConnection.class);
    // use hiraCon1...
)
Run Code Online (Sandbox Code Playgroud)

但是,如果HiraConnection是具体类而不是接口,则可能不起作用.解包通常也会导致代码变得脆弱.除非绝对必要,否则通常最好避免依赖于驱动程序特定的接口.

您对问题中代码的一些评论:

  • 如果你知道HIRAConnection hiraCon1 = (HIRAConnection) ds.getConnection();有效,那么你根本不需要打开包装.
  • 检查hiraCon1 instanceof Wrapper是一个无用的检查,因为如果HIRAConnection工具java.sql.Connection,那么它将始终贯彻执行java.sql.Wrapper(否则运行代码将产生一个ClassNotFoundExceptionjava.sql.Wrapper这意味着你运行它在Java 5或更低).
  • 检查hiraCon1.isWrapperFor(Connection.class),然后展开connHIRAConnection是不安全的,是没有意义的.如果你想解开connHIRAConnection,那么你需要使用conn.isWrapperFor(HiraConnection.class)
  • hiraCon1= ds.unwrap(HIRAConnection.class);抛出一个并不意外SQLException:javax.sql.DataSource实现不太可能认为自己是连接的包装器.
  • 检查hiraCon1.isWrapperFor(HIRAConnection.class)是一个有点奇怪:你已经知道hiraCon1 一个HIRAConnection
  • 如前所述,conn检查后展开hiraCon1是没有意义的.
  • 检查conn.isWrapperFor(Connection.class)是一个有点奇怪:你已经知道conn 一个Connection
  • 检查conn.isWrapperFor(Connection.class)然后使用conn.unwrap(com.hira.HIRAConnection.class)是不安全的,因为你只检查是否conn解包Connection,而不是HIRAConnection.