我们都知道,无论何时连接到数据库,都需要使用连接池。 所有使用JDBC 4类的现代驱动程序都支持它。 在本文中,我们将概述Spring应用程序中的连接池,以及如何在非JEE环境(例如测试)中处理相同的上下文。
在Spring,大多数连接数据库的示例都是使用DriverManagerDataSource完成的。如果您没有正确阅读文档,那么您将错过非常重要的一点。
注意: 此类不是实际的连接池; 它实际上并不合并连接。 它只是对成熟的连接池的简单替代,实现了相同的标准接口,但是在每个呼叫上都创建了新的Connections。
对于J2EE容器外部的测试或独立环境很有用,可以作为相应ApplicationContext中的DataSource bean,也可以与简单的JNDI环境结合使用。 假定使用池的Connection.close()调用将简单地关闭Connection,因此任何可识别DataSource的持久性代码都应起作用。
是的,默认情况下,spring应用程序不使用池连接。 有两种方法可以实现连接池。 取决于谁在管理池。 如果您在JEE环境中运行,则最好使用容器。 在非JEE设置中,有一些库可以帮助应用程序管理连接池。 让我们在下面详细讨论它们。
1.服务器(容器)管理的连接池(使用JNDI)
当应用程序连接到数据库服务器时,建立物理实际连接所花费的时间远远超过了脚本的执行。 连接池是数据库供应商率先采用的一种技术,它允许多个客户端共享一组提供对数据库资源访问权限的缓存的连接对象。 JavaWorld文章对此进行了很好的概述。
在J2EE容器中,建议使用容器提供的JNDI数据源。 这样的数据源可以通过JndiObjectFactoryBean在Spring ApplicationContext中作为数据源bean公开,以实现与此类之类的本地数据源bean之间的无缝切换。
以下文章帮助我在JBoss AS中设置数据源。
下一步是使用服务器从应用程序创建的这些连接。 如文档中所述,您可以为此使用JndiObjectFactoryBean 。 如下所示
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/my-ds"/>
</bean>
如果要使用springs“ SpringJUnit4ClassRunner”编写任何测试,则将无法加载上下文,因为JNDI资源将不可用。
对于测试,您可以通过Spring的SimpleNamingContextBuilder设置模拟JNDI环境,或者将Bean定义切换到本地DataSource(因此更简单)。
当我在寻找一个很好的解决方案(我不想为测试提供单独的上下文)时,这个SO答案对我有所帮助。 它很好地利用了Javadoc中给出的各种技巧。 上述解决方案的问题是重复创建JNDI连接的代码。 我已经使用自定义的运行器SpringWithJNDIRunner解决了它。 此类将JNDI功能添加到SpringJUnit4ClassRunner。 它从类路径中的“ test-datasource.xml”文件中读取数据源,并将其绑定到名称为“ java:/ my-ds”的JNDI资源。 执行此代码后,JNDI资源可用于弹簧容器使用。
import javax.naming.NamingException;
import org.junit.runners.model.InitializationError;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This class adds the JNDI capabilities to the SpringJUnit4ClassRunner.
* @author mkadicha
*
*/
public class SpringWithJNDIRunner extends SpringJUnit4ClassRunner {
public static boolean isJNDIactive;
/**
* JNDI is activated with this constructor.
*
* @param klass
* @throws InitializationError
* @throws NamingException
* @throws IllegalStateException
*/
public SpringWithJNDIRunner(Class<?> klass) throws InitializationError,
IllegalStateException, NamingException {
super(klass);
synchronized (SpringWithJNDIRunner.class) {
if (!isJNDIactive) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"test-datasource.xml");
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("java:/my-ds",
applicationContext.getBean("dataSource"));
builder.activate();
isJNDIactive = true;
}
}
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
</beans>
要使用此运行器,您只需在测试中使用注释@RunWith(SpringWithJNDIRunner.class) 。 此类扩展了SpringJUnit4ClassRunner,因为@RunWith批注中只能有一个类。 一个测试周期仅创建一次JNDI。 此类为问题提供了一种干净的解决方案。
2.应用程序管理的连接池
如果您需要J2EE容器之外的“真实”连接池,请考虑使用Apache的Jakarta Commons DBCP或C3P0。 Commons DBCP的BasicDataSource和C3P0的ComboPooledDataSource是完整的连接池bean,支持与此类相同的基本属性以及特定的设置(例如最小/最大池大小等)。
下面的用户指南可以帮助您进行配置。
以下文章介绍了配置连接池的一般准则和最佳实践。