Java HikariCP包装器(线程安全)

Java HikariCP包装器(线程安全),java,thread-safety,singleton,wrapper,hikaricp,Java,Thread Safety,Singleton,Wrapper,Hikaricp,我正在学习使用HikariCP(我是java新手),我发现了一个包装器,但我认为它不是线程安全的,单例的实例是线程安全的,而不是getConnection()方法。课程内容如下: public class HikariCPWrapper{ private static final HikariCPWrapper INSTANCE; private HikariDataSource ds; static { INSTANCE = new Hikari

我正在学习使用HikariCP(我是java新手),我发现了一个包装器,但我认为它不是线程安全的,单例的实例是线程安全的,而不是getConnection()方法。课程内容如下:

public class HikariCPWrapper{
    private static final HikariCPWrapper INSTANCE;
    private HikariDataSource ds;
    static  
    {  
    INSTANCE = new HikariCPWrapper();    
    }  

    private HikariCPWrapper(){
        HikariConfig config = new HikariConfig(); 
        //config.set... 
        //... 
        ds = new HikariDataSource(config);  

    }

    public static HikariCPWrapper getInstance ()  
    {  
        return INSTANCE;  
    }  

    public Connection getConnection()  throws SQLException  
    {  
        return ds.getConnection();  
    }  
}
我需要将参数发送到HikariConfig或HikariDataSource,所以我用这种方式重新编写:

public interface IConnectionProvider {
    void init(String jdbcUrl, String user, String password);
    Connection getConnection() throws SQLException;
}

    public class ConnectionProviderHikariCP implements IConnectionProvider{

    private static final ConnectionProviderHikariCP INSTANCE;
    private final HikariDataSource hikariDataSource;
    private Boolean initialized;
    //class initializer:
    static
    {
        INSTANCE = new ConnectionProviderHikariCP();
    }

    private ConnectionProviderHikariCP() {
        hikariDataSource = new HikariDataSource();
        initialized = false;
    }

    public static ConnectionProviderHikariCP getInstance() {
        return INSTANCE;
    }

    @Override
    public synchronized void init(String jdbcUrl, String user, String password) {
        hikariDataSource.setJdbcUrl(jdbcUrl);        
        hikariDataSource.setUsername(user);
        hikariDataSource.setPassword(password);
        initialized = true;
    }

    @Override
    public synchronized Connection getConnection() throws SQLException {
        if(!initialized)
           throw new UnsupportedOperationException("Debe inicializar mediante el método Init() primero!!!!!."); 

        return hikariDataSource.getConnection();
    }

}
IConnectionProvider connectionProvider = ConnectionProviderHikariCP.getInstance();
connectionProvider.init(url, user, passwd);

BaseDAOFactory fatory = new MySqlDAOFactory(connectionProvider);
IExerciseBO exerciseBO = new ExerciseBO(fatory); 
我这样使用它:

public interface IConnectionProvider {
    void init(String jdbcUrl, String user, String password);
    Connection getConnection() throws SQLException;
}

    public class ConnectionProviderHikariCP implements IConnectionProvider{

    private static final ConnectionProviderHikariCP INSTANCE;
    private final HikariDataSource hikariDataSource;
    private Boolean initialized;
    //class initializer:
    static
    {
        INSTANCE = new ConnectionProviderHikariCP();
    }

    private ConnectionProviderHikariCP() {
        hikariDataSource = new HikariDataSource();
        initialized = false;
    }

    public static ConnectionProviderHikariCP getInstance() {
        return INSTANCE;
    }

    @Override
    public synchronized void init(String jdbcUrl, String user, String password) {
        hikariDataSource.setJdbcUrl(jdbcUrl);        
        hikariDataSource.setUsername(user);
        hikariDataSource.setPassword(password);
        initialized = true;
    }

    @Override
    public synchronized Connection getConnection() throws SQLException {
        if(!initialized)
           throw new UnsupportedOperationException("Debe inicializar mediante el método Init() primero!!!!!."); 

        return hikariDataSource.getConnection();
    }

}
IConnectionProvider connectionProvider = ConnectionProviderHikariCP.getInstance();
connectionProvider.init(url, user, passwd);

BaseDAOFactory fatory = new MySqlDAOFactory(connectionProvider);
IExerciseBO exerciseBO = new ExerciseBO(fatory); 
但是我对java没有经验,所以我需要你的建议。 一流(原始)螺纹安全吗?
我的实现是线程安全的吗?

HikariCP本身是线程安全的。据我所知,您试图做的是在通过
init()
方法初始化
HikariDataSource
之前阻止调用方调用
getConnection()
。您可能还希望阻止对数据源的多次调用
init()

就池吞吐量而言,用synchronized包装
getConnection()
,通常是个坏主意。基于以上代码,我推荐以下模式:

public class ConnectionProviderHikariCP implements IConnectionProvider {

  private static final ConnectionProviderHikariCP INSTANCE;
  private final HikariDataSource hikariDataSource;
  private AtomicBoolean initialized;
  //class initializer:
  static
  {
     INSTANCE = new ConnectionProviderHikariCP();
  }

  private ConnectionProviderHikariCP() {
     hikariDataSource = new HikariDataSource();
     initialized = new AtomicInteger();
  }

  public static ConnectionProviderHikariCP getInstance() {
     return INSTANCE;
  }

  @Override
  public void init(String jdbcUrl, String user, String password) {
     if (initialized.compareAndSet(false, true)) {
        hikariDataSource.setJdbcUrl(jdbcUrl);        
        hikariDataSource.setUsername(user);
        hikariDataSource.setPassword(password);
     }
     else {
        throw new IllegalStateException("Connection provider already initialized.");
     }
  }

  @Override
  public Connection getConnection() throws SQLException {
     if (initialized.get()) {
        return hikariDataSource.getConnection();
     }

     throw new UnsupportedOperationException("Debe inicializar mediante el método Init() primero!!!!!."); 
  }
}

HikariCP本身是线程安全的。据我所知,您试图做的是在通过
init()
方法初始化
HikariDataSource
之前阻止调用方调用
getConnection()
。您可能还希望阻止对数据源的多次调用
init()

就池吞吐量而言,用synchronized包装
getConnection()
,通常是个坏主意。基于以上代码,我推荐以下模式:

public class ConnectionProviderHikariCP implements IConnectionProvider {

  private static final ConnectionProviderHikariCP INSTANCE;
  private final HikariDataSource hikariDataSource;
  private AtomicBoolean initialized;
  //class initializer:
  static
  {
     INSTANCE = new ConnectionProviderHikariCP();
  }

  private ConnectionProviderHikariCP() {
     hikariDataSource = new HikariDataSource();
     initialized = new AtomicInteger();
  }

  public static ConnectionProviderHikariCP getInstance() {
     return INSTANCE;
  }

  @Override
  public void init(String jdbcUrl, String user, String password) {
     if (initialized.compareAndSet(false, true)) {
        hikariDataSource.setJdbcUrl(jdbcUrl);        
        hikariDataSource.setUsername(user);
        hikariDataSource.setPassword(password);
     }
     else {
        throw new IllegalStateException("Connection provider already initialized.");
     }
  }

  @Override
  public Connection getConnection() throws SQLException {
     if (initialized.get()) {
        return hikariDataSource.getConnection();
     }

     throw new UnsupportedOperationException("Debe inicializar mediante el método Init() primero!!!!!."); 
  }
}

一切都是线程安全的。不过,我会修改代码,使其遵守Java命名约定:mathods以小写字母开头,变量不包含下划线。getConnection()不应引发异常,但应引发SQLException。静态块中的try/catch是无用的,因为构造函数不会引发任何异常。@JBNizet谢谢。那么我可以跳过在init()和getConnection()方法中同步的put吗?(我会用你的建议更新代码)。删除它们会使代码不具有线程安全性。@JBNizet哦,我不明白你的第一条评论。谢谢,一切都是线程安全的。不过,我会修改代码,使其遵守Java命名约定:mathods以小写字母开头,变量不包含下划线。getConnection()不应引发异常,但应引发SQLException。静态块中的try/catch是无用的,因为构造函数不会引发任何异常。@JBNizet谢谢。那么我可以跳过在init()和getConnection()方法中同步的put吗?(我会用你的建议更新代码)。删除它们会使代码不具有线程安全性。@JBNizet哦,我不明白你的第一条评论。非常感谢。