Spring 管理数据源

Spring 管理数据源

不管通过何种持久化技术,都必须通过数据连接访问数据库,在Spring中,数据连接是通过数据源获得的。在以往的应用中,数据源一般是Web应用服务器提供的。在Spring中,你不但可以通过JNDI获取应用服务器的数据源,也可以直接在Spring容器中配置数据源,此外,你还可以通过代码的方式创建一个数据源,以便进行无依赖的单元测试配置一个数据源。

Spring在第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP,其二是 C3P0。可以在Spring配置文件中利用这两者中任何一个配置数据源。

1. Spring 配置DataSource 的三种方式

1.1. 使用Spring自带的DriverManagerDataSource

DriverManagerDataSource建立连接是只要有连接就新建一个connection,根本没有连接池的作用。 这里的引用属性是从配置文件jdbc.properties 中读取的。

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="location" value="/WEB-INF/jdbc.properties"/>      

</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName"><value>${jdbc.driverClassName}</value></property>

    <property name="url"><value>${jdbc.url}</value></property>  

    <property name="username"><value>${jdbc.username}</value></property>

    <property name="password"><value>${jdbc.password}</value></property>

</bean>

说明:由于其没有使用连接池,故少在项目中用到。

1.2. 使用数据源

这是一种推荐使用的数据源配置方式,它真正使用了连接池技术。Spring在第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP,其二是 C3P0,这里使用了DBCP。

1.2.1  DBCP数据源:org.apache.commons.dbcp.BasicDataSource  

DBCP是一个依赖 Jakarta commons-pool对象池机制的数据库连接池,要在Spring中使用DBCP连接池,需要引入spring-framework-2.0-ml\lob\jakarta-commons文件夹中的commons-collections.jar、commons-dbcp.jar和commons-pool.jar。下面是DBCP配置片段:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">      

<property name="location" value="/WEB-INF/jdbc.properties"/>      

</bean>      

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">      

<property name="driverClassName" value="${jdbc.driverClassName}" />      

<property name="url" value="${jdbc.url}" />      

<property name="username" value="${jdbc.username}" />      

<property name="password" value="${jdbc.password}" />      

</bean>  

说明:BasicDataSource提供了close()方法关闭数据源,所以必须设定destroy-method=”close”属性, 以便Spring容器关闭时,数据源能够正常关闭。除以上必须的数据源属性外,还有一些常用的属性:

defaultAutoCommit:设置从数据源中返回的连接是否采用自动提交机制,默认值为 true;

defaultReadOnly:设置数据源是否仅能执行只读操作, 默认值为 false;

maxActive:最大连接数据库连接数,设置为0时,表示没有限制;

maxIdle:最大等待连接中的数量,设置为0时,表示没有限制;

maxWait:最大等待秒数,单位为毫秒, 超过时间会报出错误信息;

validationQuery:用于验证连接是否成功的查询SQL语句,SQL语句必须至少要返回一行数据, 如你可以简单地设置为:“select count(*) from user”;

removeAbandoned:是否自我中断,默认是 false ;

removeAbandonedTimeout:几秒后数据连接会自动断开,在removeAbandoned为true,提供该值;

logAbandoned:是否记录中断事件, 默认为 false;

1.2.2  C3P0数据源:com.mchange.v2.c3p0.ComboPooledDataSource

C3P0是一个开放源代码的JDBC数据源实现项目,它在lib目录中与Hibernate一起发布,实现了JDBC3和JDBC2扩展规范说明的 Connection 和Statement 池。C3P0类包位于/lib/c3p0/c3p0-0.9.0.4.jar。下面是C3P0配置片段:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">      

<property name="driverClass" value=" oracle.jdbc.driver.OracleDriver "/>      

<property name="jdbcUrl" value=" jdbc:oracle:thin:@localhost:1521:ora9i "/>      

<property name="user" value="admin"/>      

<property name="password" value="1234"/>      

</bean>

 

说明:ComboPooledDataSource和BasicDataSource一样提供了一个用于关闭数据源的close()方法,这样我们就可以保证Spring容器关闭时数据源能够成功释放。

C3P0拥有比DBCP更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制:

acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目;

acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30;

acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000;

autoCommitOnClose:连接关闭时默认将所有未提交的操作回滚。默认为false;

automaticTestTable: C3P0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数,那么属性preferredTestQuery将被忽略。你 不能在这张Test表上进行任何操作,它将中为C3P0测试所用,默认为null;

breakAfterAcquireFailure:获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调   用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false;

checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒,默认为0;

connectionTesterClassName: 通过实现ConnectionTester或QueryConnectionTester的类来测试连接,类名需设置为全限定名。默认为 com.mchange.v2.C3P0.impl.DefaultConnectionTester;

idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;

initialPoolSize:初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3;

maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0;

maxPoolSize:连接池中保留的最大连接数。默认为15;

maxStatements:JDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属 于单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatements与 maxStatementsPerConnection均为0,则缓存被关闭。默认为0;

maxStatementsPerConnection:连接池内单个连接所拥有的最大缓存Statement数。默认为0;

numHelperThreads:C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3;

preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认为null;

propertyCycle: 用户修改系统配置参数执行前最多等待的秒数。默认为300;

testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都 将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable

等方法来提升连接测试的性能。默认为false;

testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false。

1.2.3  其他数据源

oracle.jdbc.pool.OracleDataSource:使用Oracle自带的数据源oracle.jdbc.pool.OracleDataSource,Spring使用完这个数据源提供的数据连接后并不进行关闭操作,需要显式的关闭连接。

org.logicalcobwebs.proxool.ProxoolDataSource: Proxool是一种Java数据库连接池技术。sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。目前是和DBCP以及C3P0一起,最为常见的三种JDBC连接池技术。

com.jolbox.bonecp.BoneCPDataSource :bonecp数据连接池, BoneCP最大的特点就是效率,BoneCP号称是目前市面上最快的Java连接池,从官方的评测来看其效率远远超越了其它同类的Java连 接池产品

1.3. 使用Tomcat提供的JNDI

说明:JndiObjectFactoryBean 能够通过JNDI获取DataSource

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

   <property name="jndiName">

<value>java:comp/env/jdbc/roseindiaDB_local</value>

</property>

</bean>

总结:这种方式需要在web server中配置数据源,不方便于部署。

1.4. 总结

3种方式中的第一种没有使用连接池,故少在项目中用到,第三种方式需要在web server中配置数据源,不方便于部署,推荐使用第二种方式进行数据源的配置。

2. Spring持久化的设计思想

2.1. JDBC基本的编程模型

由于任何持久化层的封装实际上都是对java.sql.Connection等相关对象的操作,一个典型的数据操作的流程如下:

在实际使用spring和ibatis的时候,我们都没有感觉到上面的流程,其实spring已经对外已经屏蔽了上述的操作,让我们更关注业务逻辑功能

2.2. 开启事务

在开启事务的时候,我们需要初始化事务上下文信息,以便在业务完成之后,需要知道事务的状态,以便进行后续的处理,这个上下文信息可以保存在 ThreadLocal里面,包括是否已经开启事务,事务的超时时间,隔离级别,传播级别,是否设置为回滚。这个信息对应用来说是透明的,但是提供给使用者编程接口,以便告知业务结束的时候是提交事务还是回滚事务。

2.3. 获取连接

首先来看看spring如何获取数据库连接的,对于正常情况来看,获取连接直接调用DataSource.getConnection()就可以了,我们在自己实现的时候也肯定会这么做,但是需要考虑两种情况(这里面先不引入事务的传播属性):

1 还没有获取过连接,这是第一次获取连接

2 已经获取过连接,不是第一次获取连接,可以复用连接

解决获取数据库连接的关键问题就是如何判断是否已经可用的连接,而不需要开启新的数据库连接,同时由于数据库连接需要给后续的业务操作复用,如何保持这个连接,并且透明的传递给后续流程。对于一个简单的实现就是使用线程上下文变量ThrealLocal来解决以上两个问题。

具体的实现是:在获取数据库连接的时候,判断当前线程线程变量里面是否已经存在相关连接,如果不存在,就创新一个新的连接,如果存在,就直接获取其对应的连接。在第一次获取到数据库连接的时候,我们还需要做一些特殊处理,就是设置自动提交为false。在业务活动结束的时候在进行提交或者回滚。这个时候就是要调用connection.setAutoCommit(false)方法。

2.4. 执行sql

这一部分和业务逻辑相关,通过对外提供一些编程接口,可以让业务决定业务完成之后如何处理事务,比较简单的就是设置事务状态。

2.5. 提交事务

在开启事务的时候,事务上下文信息已经保存在线程变量里面了,可以根据事务上下文的信息,来决定是否是提交还是回滚。其实就是调用数据库连接Connection.commit 和 Connection.rollback 方法。然后需要清空线程变量中的事务上下文信息。相当于结束了当前的事务。  

2.6. 关闭连接

关闭连接相对比较简单,由于当前线程变量保存了连接信息,只需要获取连接之后,调用connection.close方法即可,接着清空线程变量的数据库连接信息。

上面几个流程是一个简单的事务处理流程,在spring中都有对应的实现,见TransactionTemplate.execute方法。

2.7. 总结

当一个持久化操作结束时,数据库连接就应该关闭,而spring 封装了其他操作,我们只需要关注 “执行sql”这一步。

3. Spring的底层类核心代码分析

3.1. 使用JdbcTemplate 类

JdbcTemplate类使用DataSource得到一个数据库连接。然后,他调用StatementCreator实例创建要执行的语句。下一步,他调用StatementCallBack完成。

一旦StatementCallBack返回结果,JdbcTemplate类完成所有必要清理工作关闭连接。如果StatementCreator或StatementCallBack抛出异常,JdbcTemplate类会捕获他们,并转换为Spring数据访问异常。

看一个JdbcTemplate里面的比较核心的一个方法:

  1. //-------------------------------------------------------------------------
  2. // Methods dealing with prepared statements
  3. //-------------------------------------------------------------------------
  4. public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action)
  5. throws DataAccessException {
  6. Assert.notNull(psc, "PreparedStatementCreator must not be null");
  7. Assert.notNull(action, "Callback object must not be null");
  8. if (logger.isDebugEnabled()) {
  9. String sql = getSql(psc);
  10. logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
  11. }
  12. Connection con = DataSourceUtils.getConnection(getDataSource());
  13. PreparedStatement ps = null;
  14. try {
  15. Connection conToUse = con;
  16. if (this.nativeJdbcExtractor != null &&
  17. this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {
  18. conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
  19. }
  20. ps = psc.createPreparedStatement(conToUse);
  21. applyStatementSettings(ps);
  22. PreparedStatement psToUse = ps;
  23. if (this.nativeJdbcExtractor != null) {
  24. psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);
  25. }
  26. Object result = action.doInPreparedStatement(psToUse);
  27. handleWarnings(ps);
  28. return result;
  29. }
  30. catch (SQLException ex) {
  31. // Release Connection early, to avoid potential connection pool deadlock
  32. // in the case when the exception translator hasn‘t been initialized yet.
  33. if (psc instanceof ParameterDisposer) {
  34. ((ParameterDisposer) psc).cleanupParameters();
  35. }
  36. String sql = getSql(psc);
  37. psc = null;
  38. JdbcUtils.closeStatement(ps);
  39. ps = null;
  40. DataSourceUtils.releaseConnection(con, getDataSource());
  41. con = null;
  42. throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);
  43. }
  44. finally {
  45. if (psc instanceof ParameterDisposer) {
  46. ((ParameterDisposer) psc).cleanupParameters();
  47. }
  48. JdbcUtils.closeStatement(ps);
  49. DataSourceUtils.releaseConnection(con, getDataSource());
  50. }
  51. }

显然,我们在finally里面看到了关闭调用,而且从代码可以看出 JdbcTemplate是调用了DataSourceUtils的。在 Spring文档中要求尽量首先使用JdbcTemplate,其次是用DataSourceUtils来获取和释放连接

再看看这个关闭调用方法内部:

  1. /**
  2. * Close the given Connection, obtained from the given DataSource,
  3. * if it is not managed externally (that is, not bound to the thread).
  4. * @param con the Connection to close if necessary
  5. * (if this is <code>null</code>, the call will be ignored)
  6. * @param dataSource the DataSource that the Connection was obtained from
  7. * (may be <code>null</code>)
  8. * @see #getConnection
  9. */
  10. public static void releaseConnection(Connection con, DataSource dataSource) {
  11. try {
  12. doReleaseConnection(con, dataSource);
  13. }
  14. catch (SQLException ex) {
  15. logger.debug("Could not close JDBC Connection", ex);
  16. }
  17. catch (Throwable ex) {
  18. logger.debug("Unexpected exception on closing JDBC Connection", ex);
  19. }
  20. }
  21. /**
  22. * Actually close the given Connection, obtained from the given DataSource.
  23. * Same as {@link #releaseConnection}, but throwing the original SQLException.
  24. * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
  25. * @param con the Connection to close if necessary
  26. * (if this is <code>null</code>, the call will be ignored)
  27. * @param dataSource the DataSource that the Connection was obtained from
  28. * (may be <code>null</code>)
  29. * @throws SQLException if thrown by JDBC methods
  30. * @see #doGetConnection
  31. */
  32. public static void doReleaseConnection(Connection con, DataSource dataSource) throws SQLException {
  33. if (con == null) {
  34. return;
  35. }
  36. if (dataSource != null) {
  37. ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
  38. if (conHolder != null && connectionEquals(conHolder, con)) {
  39. // It‘s the transactional Connection: Don‘t close it.
  40. conHolder.released();
  41. return;
  42. }
  43. }
  44. // Leave the Connection open only if the DataSource is our
  45. // special SmartDataSoruce and it wants the Connection left open.
  46. if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
  47. logger.debug("Returning JDBC Connection to DataSource");
  48. con.close();
  49. }
  50. }

主要下面这几行代码:

  1. // Leave the Connection open only if the DataSource is our
  2. // special SmartDataSoruce and it wants the Connection left open.
  3. if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
  4. logger.debug("Returning JDBC Connection to DataSource");
  5. con.close();
  6. }

可以看到大部分情况下是自动关闭,除非你使用的是SmartDataSource,且SmartDataSource指定了允许关闭。

3.2. 使用DataSourceUtils

使用Spring 对DataSource进行事务管理的关键在于ConnectionHolder和TransactionSynchronizationManager。

0.先从TransactionSynchronizationManager中尝试获取连接

1.如果前一步失败则在每个线程上,对每个DataSouce只创建一个Connection

2.这个Connection用ConnectionHolder包装起来,由TransactionSynchronizationManager管理

3.再次请求同一个连接的时候,从TransactionSynchronizationManager返回已经创建的ConnectionHolder,然后调用ConnectionHolder的request将引用计数+1

4.释放连接时要调用ConnectionHolder的released,将引用计数-1

5.当事物完成后,将ConnectionHolder从TransactionSynchronizationManager中解除。当谁都不用,这个连接被close

以上所有都是可以调用DataSourceUtils化简代码。

而JdbcTemplate又是调用DataSourceUtils的。所以在Spring文档中要求尽量首先使用JdbcTemplate,其次是用DataSourceUtils来获取和释放连接。至于TransactionAwareDataSourceProxy,那是下策的下策。不过可以将Spring事务管理和遗留代码无缝集成。

如使用Spring的事务管理,但是又不想用JdbcTemplate,那么可以考虑TransactionAwareDataSourceProxy。这个类是原来DataSource的代理。

其次,想使用Spring事物,又不想对Spring进行依赖是不可能的。与其试图自己模拟DataSourceUtils,不如直接使用现成的

此外,如果使用DataSourceUtils类,则得到连接方法DataSourceUtils.getConnection()要与释放连接方法DataSourceUtils.releaseConnection()配合使用。

3.3. 总结

由底层代码可以看出,使用JdbcTemplate 来连接数据库不需要手动关闭连接,但是,有时还需要自己额外的拿到conn进行操作,如下: jdbcTemplate.getDataSource().getConnection() ,那么,就需要关闭连接了

而如果采用其他底层方法的话,需要使用对应的释放连接。

4. Spring的数据源实现类

4.1. 使用JDBC 模板来实现

Spring JDBC实现模板设计模式,这意味着,代码中的重复的复杂的任务部分是在模板类中实现的。JdbcTemplate是core包的核心类。它替我们完成了资源的创建以及释放工作,从而简化了我们对JDBC的使用。它还可以帮助我们避免一些常见的错误,比如忘记关闭数据库连接。JdbcTemplate将完成JDBC核心处理流程,比如SQL语句的创建、执行,而把SQL语句的生成以及查询结果的提取工作留给我们的应用代码。它可以完成SQL查询、更新以及调用存储过程,可以对ResultSet进行遍历并加以提取。它还可以捕获JDBC异常并将其转换成org.springframework.dao包中定义的,通用的,信息更丰富的异常。

SpringJdbcTemplate的工作流程如下:

(1).配置数据源:

在applicationContext.xml中设置好数据源。

Spring中,将管理数据库连接的数据源当作普通Java Bean一样在Spring IoC容器中管理,当应用使用数据源时Spring IoC容器负责初始化数据源。

(2).将数据源注入JdbcTemplate:

JdbcTemplate中dataSource属性用于注入配置的数据源,Spring IoC容器通过依赖注入将配置的数据源注入到Spring对Jdbc操作的封装类JdbcTemplate中。

(3).应用中使用JdbcTemplate:

注入了数据源的JdbcTemplate就可以在应用中使用了,应用中对数据源的增删改查等操作都可以使用JdbcTemplate对外提供的方法操作数据库。

实例参考:http://blog.csdn.net/chjttony/article/details/6404089

4.2. 使用DriverManagerDataSource类来实现

Spring本身也提供了一个简单的数据源实现类DriverManagerDataSource ,它位于org.springframework.jdbc.datasource包中。这个类实现了javax.sql.DataSource接口,但 它并没有提供池化连接的机制,每次调用getConnection()获取新连接时,只是简单地创建一个新的连接。因此,这个数据源类比较适合在单元测试 或简单的独立应用中使用,因为它不需要额外的依赖类。

说明:

DriverManagerDataSource :简单封装了DriverManager获取数据库连接;通过DriverManager的getConnection方法获取数据库连接;

SingleConnectionDataSource :内部封装了一个连接,该连接使用后不会关闭,且不能在多线程环境中使用,一般用于测试;

LazyConnectionDataSourceProxy :包装一个DataSource,用于延迟获取数据库连接,只有在真正创建Statement等时才获取连接,因此再说实际项目中最后使用该代理包装原始DataSource从而使得只有在真正需要连接时才去获取。

DataSourceUtils: Spring JDBC抽象框架内部都是通过它的getConnection(DataSource dataSource)方法获取数据库连接,releaseConnection(Connection con, DataSource dataSource) 用于释放数据库连接,DataSourceUtils用于支持Spring管理事务,只有使用DataSourceUtils获取的连接才具有Spring管理事务。

4.3. 使用spring 的getSession()

Spring与hibernate 集成的环境里,getSession获取的是没有经过Spring包装的原始的session,使用完之后不会自动关闭,需要调用手动调用close方法,或者releaseSession(session);而getHibernateTemplate()方法是经过spring封装的,例如添加相应的声明式事务管理,由spring管理相应的连接,所以用getHibernateTemplate().find这些方法之后,spring会帮你控制数据库连接的关闭。

在实际的使用过程中发现的确getHibernateTemplate()比getSession()方法要好很多,但是有些方法在getHibernateTemplate()并没有提供,这时我们用HibernateCallback回调的方法管理数据库.

例如如下代码:

return this.getHibernateTemplate().executeFind(new HibernateCallback(){

public List doInHibernate(Session session) throws HibernateException, SQLException {

Query query=session.createQuery(hqlString);

query.setFirstResult(startRow1);

query.setMaxResults(pageSize1);

return query.list();

}

});

但是,如果是配置了OpenSessionInView模式,则getSession拿到的session,Spring就会负责关闭了!

 

5. Spring中bean的scope 详解

在spring2.0之前bean只有2种作用域即:singleton(单例)、non-singleton(也称 prototype), Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对 Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类 型,满足实际应用需求。

<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>   这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。

5.1. singleton作用域(scope 默认值)

当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把 一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时 候,spring的IOC容器中只会存在一个该bean。

配置实例:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>

或者

<bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>

5.2. prototype

prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。)

配置实例:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>

或者

<beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/>

5.3. request

request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例:

request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置:

如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可:

<web-app>

...

<listener>

<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

</listener>

...

</web-app>

,如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现:

<web-app>

..

<filter>

<filter-name>requestContextFilter</filter-name>

<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>requestContextFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

...

</web-app>

接着既可以配置bean的作用域了:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>

5.4.  session

session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例:

配置实例:

和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>

5.5.  global session

global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。

配置实例:

和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>

5.6.  自定义bean装配作用域

在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和 prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope来定 义,自定义自己的作用域只要实现该接口即可,下面给个实例:

我们建立一个线程的scope,该scope在表示一个线程中有效,代码如下:

publicclass MyScope implements Scope {

privatefinal ThreadLocal threadScope = new ThreadLocal() {

protected Object initialValue() {

returnnew HashMap();

}

};

public Object get(String name, ObjectFactory objectFactory) {

Map scope = (Map) threadScope.get();

Object object = scope.get(name);

if(object==null) {

object = objectFactory.getObject();

scope.put(name, object);

}

return object;

}

public Object remove(String name) {

Map scope = (Map) threadScope.get();

return scope.remove(name);

}

publicvoid registerDestructionCallback(String name, Runnable callback) {

}

public String getConversationId() {

// TODO Auto-generated method stub

returnnull;

}

}

6. 使用Spring操作数据库需要显式关闭数据库连接的情况

1、 配置数据源时,需要添加 destroy-method 属性,DBCP和C3PO 都提供了close()方法关闭数据源,所以必须设定destroy-method=”close” 属性, 以便Spring容器关闭时,数据源能够正常关闭

2、 如果使用spring 中 bean 的作用域为 prototype ,需要在应用程序中 手动关闭数据库

3、 使用JdbcTemplate 来连接数据库不需要手动关闭连接,但是,有时还需要自己额外的拿到conn进行操作,如下: jdbcTemplate.getDataSource().getConnection() 那么,就需要关闭连接了

4、 直接使用DataSourceUtils.getConnection()方法得到连接,则需要使用DataSourceUtils.releaseConnection()方法 来释放连接了

5、 若是使用的是比DataSourceUtils 更底层的代码,则必须要显式关闭连接了

时间: 2024-10-10 03:07:01

Spring 管理数据源的相关文章

mybatis如何由spring管理数据源(mybatis和spring的交互流程)

本文章比较枯燥,源码居多.都是本人一步一步debug出来的,如果有问题欢迎指出.为了体现流程连贯性,所以由很多无用步骤.读者可以一边看一边debug.如果简单可以自行略过. 在前面的章节中我们已经知道mybatis在初始化过程.(org.mybatis.spring.SqlSessionFactoryBean的afterPropertiesSet())在初始化mybatis的时候会将所有配置封装到Configuration类中,由JVM加载到内存中.这样做的好处是内存级操作是最快的,无需重复读取

Spring多数据源分布式事务管理/springmvc+spring+atomikos[jta]+druid+mybatis

项目进行读写分离及分库分表,在一个业务中,在一个事务中处理时候将切换多个数据源,需要保证同一事务多个数据源数据的一致性.此处使用atomikos来实现:最后附源码: 1:spring3.0之后不再支持jtom[jta]了,第三方开源软件atomikos(http://www.atomikos.com/)来实现. 2:org.springframework.transaction.jta.JotmFactoryBean类,spring-tx-2.5.6.jar中有此类,spring-tx-3.0.

spring 动态数据源

1.动态数据源:  在一个项目中,有时候需要用到多个数据库,比如读写分离,数据库的分布式存储等等,这时我们要在项目中配置多个数据库. 2.原理:   (1).spring 单数据源获取数据连接过程: DataSource --> SessionFactory --> Session  DataSouce   实现javax.sql.DateSource接口的数据源,  DataSource  注入SessionFactory, 从sessionFactory 获取 Session,实现数据库的

spring(16)------spring的数据源配置

在spring中,通过XML的形式实现数据源的注入有三种形式. 一,使用spring自带的DriverManagerDataSource 使用DriverManagerDataSource配置数据源与直接使用jdbc在效率上没有多大的区别,使用DriverManagerDataSource配置数据源 的代码实例如下,这里重点研究spring的数据源配置,就采用spring编程式事务处理来来研究数据源的配置. 所需要的jar包和spring编程式配置:http://blog.csdn.net/yh

Spring多数据源的配置和使用

1. 配置多个数据源 最近开发一个数据同步的小功能,需要从A主机的Oracle数据库中把数据同步到B主机的Oracle库中.当然能够用dmp脚本或者SQL脚本是最好,但是对于两边异构的表结构来说,直接导入不可行.然后在需要实时同步的情况下用存储过程也不可行了.写一个数据同步的小程序是个不错的选择.使用框架的封装和连接池是必须的,Spring是首选,这里我们同样需要Spring的多数据源连接配置方式. 其实再进行项目开发的时候,一个项目有可能不止用到一个数据源,为了提高数据库的水平伸缩性,需要对多

spring的数据源

Spring提供了两个这样的数据源(都位于org.springframework.jdbc.datasource程序包里):        DriverManagerDataSource:在每个连接请求时都新建一个连接.与DBCP的BasicDataSource不同,DriverManagerDataSource提供的连接没有进行池管理.        SingleConnectionDataSource:在每个连接请求时都返回同一个连接.虽然它不同严格意义上的池管理数据源,但我们可以把它看作只

spring配置数据源连接池

spring配置详解-连接池配置(转载) 一.连接池概述 数据库连接池概述: 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个 应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是针对这个问题提出来的. 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个:释放空闲时 间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏.这项技术

Spring管理Hibernate

为什么要用Hibernate框架? 既然用Hibernate框架访问管理持久层,那为何又提到用Spring来管理以及整合Hibernate呢? 首先我们来看一下Hibernate进行操作的步骤.比如添加用户的一个步骤. 看截图,可以看出,Hibernate操作的步骤如下: 1.      获得Configuration对象 2.      创建SessionFactory 3.      创建Session 4.      打开事务 5.      进行持久化操作.比如上面的添加用户操作 6. 

个人理解去搭建SSH三大框架spring管理配置文件(初学第一次接触SSH)

<bean id="dataSuorces" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="oracle.jdbc.OracleDirver"/>(oracle数据库) <property name="url"