我有一些现有的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连接。以下是一些想法:
每个请求都会创建一个新的JDBC连接并实例化所需的Dao对象。连接创建和Dao实例化显然都很昂贵
每个请求从JNDI数据源获取连接并实例化所需的Dao对象。这消除了连接创建的开销,但保留了准备所有语句的开销
每个请求都从JDNI数据源获取连接并实例化所需的Dao对象,但构造函数不再准备语句,它们是根据需要延迟准备的。
HttpSessionListener实例化Dao对象并将它们存储在会话中(使用setAttribute)。会话到期时,连接将关闭。
创建无状态会话bean。 bean将实例化所需的Dao对象。
选项1不是一个真正的竞争者,只是在那里展示我的思考过程。
选项2和3可以工作,但似乎不是最优的,不得不为每个请求准备语句似乎是一个容易避免的开销,但我想我错过了
选项4避免了在每次调用时准备语句的开销,但代价是手动维护状态。我不认为这是Servlet / JSP应用程序中的预期使用模式(保持连接一段时间)。
选项5应该可以工作但似乎需要很多开销,这意味着我需要一个完整的EJB容器而不是一个简单的servlet引擎。
考虑到以下目标的人们采用了哪些方法:
答案 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注入。
我希望你找到这个有用的