gpt4 book ai didi

java - 错误使用 JDBC 连接池

转载 作者:行者123 更新时间:2023-11-29 01:12:24 26 4
gpt4 key购买 nike

我正在运行一个 Spring MVC 应用程序,该应用程序由我使用 JDBC 访问的 MySQL 数据库提供支持。我使用相同的代码已经有一段时间了,但从未真正了解我是否正确使用它(正确使用连接池等)。

我知道那里有 JDBCTemplate,我考虑过使用它,但如果唯一的优点是我不必为其编写样板代码,那么我不太相信我应该使用它。事实上,与 JDBCTemplate 代码相比,我更喜欢代码的可读性。

下面是我的 DAO 中的代码,出于某种原因,我觉得我没有正确使用 ConnectionPooling。

public Agent get(Integer id){
ConnectionPool pool = new ConnectionPool();
Connection connection = pool.getConnection();
PreparedStatement ps = null;
try{
String query = "SELECT * FROM agent where id= ?";
ps = connection.prepareStatement(query);
ps.setInt(1,id);
ResultSet rs = ps.executeQuery();

Agent agent = null;
if(rs.next()){
agent = new Agent();
agent.setFirstName(rs.getString(1));
agent.setLastName(rs.getString(2));
agent.setStreet(rs.getString(3));
agent.setCity(rs.getString(4));
agent.setZip(rs.getString(5));
agent.setState(rs.getString(6));
agent.setUsername(rs.getString(7));
agent.setPassword(rs.getString(8));
agent.setId(rs.getInt(9));
agent.setEmail(rs.getString(10));
}
return agent;
}
catch(SQLException e)
{
e.printStackTrace();
return null;
}
finally{
ConnectionUtility utility = new ConnectionUtility();
utility.closePreparedStatement(ps);
pool.freeConnection(connection);
}
}

上面的代码是我最担心的不正确,但我有一些实用程序类也可能导致不良实践/不正确的代码。

下面是我的 ConnectionUtility 类(class)。
public class ConnectionUtility{

public static void closeStatement(Statement s){
try{
if(s != null){
s.close();
}
}
catch(SQLException e){
e.printStackTrace();
}
}
public void closePreparedStatement(Statement ps){
try{
if(ps != null){
ps.close();
}
}
catch(SQLException e){
e.printStackTrace();
}
}
public static void closeResultSet(ResultSet rs){
try{
if(rs != null){
rs.close();
}
}
catch(SQLException e){

}
}

}

这是我的 ConnectionPool 类(class),
public class ConnectionPool {
private static ConnectionPool pool = null;

public ConnectionPool(){
}
public static ConnectionPool getInstance(){
if(pool == null){
pool = new ConnectionPool();
}
return pool;
}

@SuppressWarnings("static-access")
public Connection getConnection(){
try{

return ConnectionFactory.getInstance().getConnection();
}
catch(SQLException e){
e.printStackTrace();
return null;
}

}
public void freeConnection(Connection c){
try{
c.close();
}
catch(SQLException e){
e.printStackTrace();
}
}
}

再一次,我觉得我确实错误地使用了所有这些类,即使一切正常,但没有任何东西在生产中进行测试。

我更喜欢使用 JDBC,因此请不要建议您切换到另一个。

最佳答案

之一核心 Spring的原理是dependency injection . Spring 基于这样一种信念,即将类使用的组件注入(inject)到该类中会导致代码比拥有类/代码(例如您的 get())更易于阅读、更易于测试和更易于维护。 method) 负责查找自己的依赖项。

作为一个更具体的例子:你的 get()方法至少依赖于其他两个类:1)“连接池”和 2)连接本身。 get()方法对如何获取这些实例有深入的了解。

作为您此处编码风格的替代方案,使用 DI 方法拥有您的 get() 的类方法将具有 Connection (或 Datasource )注入(inject)其中(通过 setter 或构造函数注入(inject))。

现在,为什么这个简单的改变会让代码更简单更好?

因为get()方法不再需要关注不是其核心职责的细节。 get() 的核心职责方法是知道如何获得 Agent给定一个 Integer id .为什么此方法还需要知道 1)从哪里获取连接和 2)您要池连接?

当您想更改此连接逻辑时会发生什么?您需要接触应用程序中每种数据访问方法的代码。这将是一个比它需要的更难的改变。

这就是依赖注入(inject)的威力:它允许您更改细节(例如 JDBC 连接的来源),而无需更改碰巧使用这些细节的代码。

至于您的实际连接池代码,您似乎误解了两个概念:

1) 您的 ConnectionPool声称想要成为单例,但您公开了一个公共(public)构造函数,允许协作者完全默认拥有 ConnectionPool 的单个实例的目的.

2)您的连接池实际上不是连接池!连接池的想法是打开到数据库的 N 个连接,然后将这 N 个连接中的每一个分发给需要按需连接的代码。这里的核心思想是您可以回收连接并避免为每个请求打开新连接的昂贵成本。在连接池中,当使用连接的代码使用它的连接完成时,物理连接实际上并没有终止 - 相反,连接句柄只是返回到池中以供另一个请求/线程/方法再次使用。

最重要的是,在使用连接池的应用程序中,负责数据访问的代码通常甚至不知道它的连接正在被池化——相反,DAO 只是引用了 DataSource。接口(interface)和 DAO 不知道当它询问 DataSource 时实际发生了什么连接或释放连接时会发生什么。因此,您可以从负责高阶逻辑的代码中抽象出“我如何连接”的细节,例如“我如何从这个整数中获取代理?”。这种抽象允许您在不重写所有其他层的情况下更改应用程序的一层 - 您已经解耦了这些层,每个层只关心它实际负责的内容。

我强烈,强烈建议您多阅读一些关于连接池的想法以及 Dependency Injection 的内容。 .为什么你会在没有 DI 组件的情况下使用 Spring?至于连接池,为什么要花时间重新发明轮子来编写自己的而不是使用许多已经存在和流行的库,如 commons-dbcpc3p0 ?与其重新发明轮子,不如使用现有的库(与自制解决方案相比,它不太可能出现错误)并专注于构建您的实际应用程序。

关于java - 错误使用 JDBC 连接池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3973881/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com