Servlet / JSP应用程序中JDBC连接的方法

时间:2014-02-17 11:11:13

标签: java jsp servlets jdbc

我有一些现有的Java代码,形式是多个DAO类,例如

class EmployeeDao {    

   public EmployeeDao(Connection conn) {
      // Prepare statements to be used by the methods below
   }

   public Employee getEmployeeById(long id) {
   }

   public Collection<Employee> getEmployeesByDepartment(long departmentId) {
   }
   ...
}

所有DAO类都使用JDBC连接构建。构造函数准备方法所需的任何语句。这在单线程环境(例如批处理)中工作正常,其中调用者可以创建连接并使用该连接实例化所需的Dao对象。

我希望能够在Java Web应用程序中使用它,但我只是不确定如何处理JDBC连接。以下是一些想法:

  1. 每个请求都会创建一个新的JDBC连接并实例化所需的Dao对象。连接创建和Dao实例化显然都很昂贵

  2. 每个请求从JNDI数据源获取连接并实例化所需的Dao对象。这消除了连接创建的开销,但保留了准备所有语句的开销

  3. 每个请求都从JDNI数据源获取连接并实例化所需的Dao对象,但构造函数不再准备语句,它们是根据需要延迟准备的。

  4. HttpSessionListener实例化Dao对象并将它们存储在会话中(使用setAttribute)。会话到期时,连接将关闭。

  5. 创建无状态会话bean。 bean将实例化所需的Dao对象。

  6. 选项1不是一个真正的竞争者,只是在那里展示我的思考过程。

    选项2和3可以工作,但似乎不是最优的,不得不为每个请求准备语句似乎是一个容易避免的开销,但我想我错过了

    选项4避免了在每次调用时准备语句的开销,但代价是手动维护状态。我不认为这是Servlet / JSP应用程序中的预期使用模式(保持连接一段时间)。

    选项5应该可以工作但似乎需要很多开销,这意味着我需要一个完整的EJB容器而不是一个简单的servlet引擎。

    考虑到以下目标的人们采用了哪些方法:

    1. 尽可能避免就每个请求准备陈述
    2. 最好使用简单的servlet引擎
    3. PS:我知道像Hibernate和Entity Beans这样的框架可以抽象出一些这样的框架,但是我想要解决“无框架”基础案例。

1 个答案:

答案 0 :(得分:5)

我建议您使用数据库连接池,就像您可以在每个主要应用程序服务器(或任何体面的实现,如dbcp,c3p0等)中找到的那样。

Spring可以在(或多或少)缓存的dao实例中为您的数据源注入引用做得很好,这样您就可以获得更多的性能(在时间和内存消耗方面)。

但是,我会说你每次都准备你的语句而不是尝试缓存它们,因为它们仍然链接到它们的创建连接,并且这些连接由数据源管理。

最后,关于你对准备声明的时间的关注:如果你仔细写下你的疑问,这可能是可以忽略的。在准备声明的过程中没有消耗时间;真正重要的是查询计划,它在数据库中在幕后完成。这就是您“首次”执行查询看起来更耗时的原因。但是,如果将参数化查询写入语句,则数据库将缓存查询执行计划,并在其后的每个查询执行中重复使用它。例如:

PreparedStatement stmt =  conn.prepareStatement("select name from employees where number = ?");

可缓存,每次准备此语句时都会重复使用查询计划(数据库'记住'它为另一个语句准备了它)

但是,这个:

PreparedStatement stmt =  conn.prepareStatement("select name from employees where number = " + employeeNumber);

意味着您的数据库必须为每次准备语句时准备一个不同的执行计划(它不会“记住”该查询) - 性能问题将与我构建查询而不是java的方式有关声明对象。更不用说这种方式是不安全的,也容易出现SQL注入。

我希望你找到这个有用的