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

时间:2018-06-15 16:53:27

标签: java jdbc

我想知道在JDBC中验证isWrapperFor和解包函数的正确方法。这里使用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");
    }
}

2 个答案:

答案 0 :(得分:5)

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

isWrapperFor(Class<?> iface)

  

如果这实现了interface参数或者是,则返回true   直接或间接的对象的包装器。返回   否则是假的。如果这实现了接口,则返回true,   否则如果这是一个包装器,则返回递归的结果   在包装对象上调用isWrapperFor。如果没有   实现接口并且不是包装器,返回false。这个   方法应该作为低成本操作来实现   unwrap以便调用者可以使用此方法来避免代价unwrap   可能会失败的电话。如果此方法返回true,则调用unwrap   相同的论点应该成功。

     

<强>参数
      iface - 定义界面的类   的返回
      如果这实现了接口,或者直接或间接包装了一个对象,则为true。

对于unwrap(Class<T> iface)

  

返回实现给定接口以允许访问的对象   非标准方法,或代理未公开的标准方法。   如果接收器实现了接口,那么结果就是   接收器或接收器的代理。如果接收器是一个包装器   包装对象实现接口,然后结果是   包装对象或包装对象的代理。否则返回   在递送的包装对象上递归调用unwrap的结果   该结果的代理。如果接收器不是包装器而不是   实现接口,然后抛出SQLException

     

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

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

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

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

Connection conn = ds.getConnection();
if (conn.isWrapperFor(HiraConnection.class)) {
    HIRAConnection hiraCon1 = conn.unwrap(HiraConnection.class);
    // use hiraCon1...
)

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

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

  • 如果您知道HIRAConnection hiraCon1 = (HIRAConnection) ds.getConnection();有效,那么您根本不需要打开包装。
  • 检查hiraCon1 instanceof Wrapper是无用的检查,因为如果HIRAConnection实现了java.sql.Connection,那么它将始终实现java.sql.Wrapper(否则运行代码会生成ClassNotFoundException 1}} for java.sql.Wrapper意味着你在Java 5或更低版本上运行它。
  • 检查hiraCon1.isWrapperFor(Connection.class),然后将conn展开到HIRAConnection是不安全的,没有任何意义。如果您要将conn展开到HIRAConnection,则需要使用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

答案 1 :(得分:0)

除非下面的@MarkRotteveel指出,否则它们并不适用于应用程序。 JDBC驱动程序作者更多地使用它们,例如Apache DBCP。