DAO(Data Access Object)用于访问数据的对象,DAO 屏蔽了数据储存的最终介质和具体的实现技术细节;
Spring 提供了一套完善的DAO体系,用于屏蔽各种持久化技术的实现细节,以统一的管理方式进行管理;

统一的DAO异常体系

Spring 提供了一套和实现技术无关的、面向 DAO 层语义的异常体系,并通过转换器将不同的持久化技术的异常转换为Spring 的异常;

Spring DAO异常体系

Spring 以分类的方式建立了异常分类目录,对于大部分应用来说,该异常分类目录对于异常类型的划分具有适当的颗粒度;
Spring DAO(1):基础 & 数据源配置

异常转换器

对于不同持久化技术的异常转换为 Spring DAO异常,Spring 提供以下的异常转化器:
持久化技术 异常转化器
JDBC org.springframework.jdbc.support.SQLExceptionTranslator
Hibernate org.springframework.orm.hibernateX.SessionFactoryUtils
MyBatis 使用JDBC的异常转化器
JPA org.springframework.orm.jpa.EntiryManagerFactoryUtils
JDO org.springframework.orm.jdo.PersistenceManagerFactoryUtils
※ Spring 4.0 对于 Hibernate 只支持 Hibernate 3.6 之后的版本;


数据访问模板支持

Spring DAO 为不同持久化技术提供了统一的模板,分别提供不同的模板类给予支持;
持久化技术 模板类 支持类
JDBC org.springframework.jdbc.core.JdbcTemplate org.springframework.jdbc.core.JdbcSupport
Hibernate org.springframework.orm.hibernateX.HibernateTemplate org.springframework.orm.hibernateX.HibernateDaoSupport
MyBatis 直接使用 JDBC 的模板类和支持类
JPA org.springframework.orm.jpa.JpaTemplate org.springframework.orm.jpa.JpaDaoSupport
JDO org.springframework.orm.jdo.JdoTemplate org.springframework.orm.jdo.JdoDaoSupport


数据源配置

对于任何持久化技术,都需要数据连接,Spring 中数据连接时以通过数据源获取的;
Spring 主要使用的数据源有3种:
  • Apache DBCP 数据源
  • C3P0 数据源
  • JNDI 数据源

DBCP 数据源

DBCP 是一个依赖 Jakarta commons-pool 对象池机制的数据库连接池,所以在类路径下需要包含 commons-pool 类包;
使用 DBCP 数据源需要 commons-dbcp:commons-dbc 依赖包(已经包含 commons-pool 类包);
以下是使用 DBCP 配置 MySQL 数据源的片段:
 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close"
      p:dirverClassName="com.mysql.jdbc.Driver"
      p:url="jdbc:mysql://127.0.0.1:3306/sampleDB"
      p:username="root"
      p:password="1234"/>

以上配置的属性为必要属性,其中 destory-method 为配置数据源相应的关闭方法,以下是一些常用的配置属性:
分类 属性 默认值 说明
事务属性 defaultAutoCommit true 连接池创建的连接默认 auto-commit 状态;
defaultReadOnly 驱动默认 连接池创建的连接默认 read-only 状态;
defaultTransactionIsolation 驱动默认 连接池创建的连接默认 transactionIsolation 状态;
可选值: NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE
数据连接属性 initialSize 0 初始化连接:连接池启动格式创建的初始化连接数量;
maxActive 8 最大活动连接:连接池中允许的保持活动状态的最大连接池数量,超过的活动连接将被释放,设置为负数值则不限制;
maxIdle / minIdle 8 / 0 最大/最小 空闲连接;
maxWait -1(无限) 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间(毫秒单位),超过时间则抛出异常;
缓存设置 poolPreparedStatements false 开始连接池的 prepared statement 功能,所有 CallableStatement 和 PreparedStatement 都会被缓存起来
maxOpenPreparedStatments 0(无限制)  PreparedStatement 池能够同时分配的打开的 statements 的最大数量;
连接泄露回收 removeAbandoned false 标记是否删除可能存在泄露的连接,该条件在 (getNumIdle() <2) and (getNumActive() > getMaxActive() -3) 满足时触发;
removeAbandonedTimeout 300 泄露的连接可以被回收的超时值(单位秒)
连接维护和检测 validationQuery 指定一个 SQL SELECT 语句,在将连接返回给调用者之前,使用该 SQL 语句验证从连接池中取出的连接是否可用;
testOnBorrow true 是否从连接池中取出来连接前进行检验,如果检验失败,则从连接池中取出该连接并尝试取出另一个连接;
testOnReturn false 是否在归还到链接池中前进行检验;
testWhileIdle false 连接是否被空闲连接回收期进行检验,如果验证失败,则从连接池中去除;
timeBetweenEvicitionRunsMills -1 空闲连接线程的运行周期(单位毫秒),设置为负数不运行空闲连接回收线程;
numTestsPerEvicitionRun 3 在每次空闲连接回收器线程运行时检查的连接数量;
minEvictabledIdleTimeMills 100 *60*30 连接在连接池存空闲时间达到该值时,空闲回收器将其进行回收(单位毫秒)

C3P0 数据源

C3P0 是一个开源的 JDBC 数据源实现项目,实现了 JDBC3 和 JDBC2 拓展规范说明的 Connection 和 Statement 池;
使用 DBCP 数据源需要 com.mchange:c3p0 依赖包;
以下是使用 DBCP 配置 MySQL 数据源的片段:
 
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destory-method="close"
      p:dirverClass="com.mysql.jdbc.Driver"
      p:jdbcUrl="jdbc:mysql://127.0.0.1:3306/sampleDB"
      p:username="root"
      p:password="1234"/>
C3P0 除了包含以上 CBCP 拥有的配置属性外,还包含以下更多常用的配置:
属性 默认值 说明
acquireIncrement 3 当连接池中的连接用完时,C3P0 一次性创建新连接的数目;
acquireRetryAttempts 30 从数据库获取新连接失败后重复尝试获取的次数;
acquireRetryDelay 1000 参数获取连接的间隔时间(单位毫秒);
autoCommitOnClose false 连接关闭时默认将所有未提交的操作回滚;
propertyCycle 300 用户修改系统配置参数执行前的最多等待参数(单位秒)
breakAfterAquireFailure false 声明为false,获取连接失败将会引起所有等待获取连接的线程抛出异常,大概数据源仍有效保留,并在下次调用 getConnection() 时继续尝试获取连接;声明为 true 时数据源将断开并永久关闭;
checkoutTimeout 0(无限) 当连接池用完时,客户端调用 getConnection() 方法后等待获取新连接的时间,超出后抛出 SQLException (单位毫秒)
idleConnectionTestPeriod 0(不检查) 间隔多少秒检查所有连接池的空闲连接(单位秒);
initialPoolSize 3 初始化时创建的连接数;
minPoolSize / maxPoolSize 0 / 15 连接池中保留的最小 / 最大连接数量;
maxIdleTime 0(不限制) 连接的最大空闲时间(单位毫秒);
maxStatements 0 JDBC 的标准参数,用于控制数据源内加载 PreparedStatement 数量,
maxStatementsPerConnection 0 连接池内单个连接所拥有的最大缓存 Statements数,当maxStatements 和 maxStatementsPerConnection 同时设置为 0 时,缓存关闭;
numHelperThreads 3 C3P0 是异步操作的,缓慢的 JDBC 通过帮助进程完成,拓展这些操作可以有效提高性能;

JNDI 数据源

如果应用配置在高性能的应用服务器(WebLogic、WebSphere等)上,则可能更希望使用应用服务器本身提供的数据源(当该数据源使用 JNDI 开放时),Spring 提供了引用 JNDI 数据源的 JndiObjectFactoryBean 类;
以下是一个引用 JNDI 源的片段:
 
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
      p:jndiName="java:comp/env/jdbc/bbt" />
<!-- jndiName 指向引用的 JNDI 数据源-->
Spring 为获取 Java EE 资源提供了一个 jee 命名空间,通过 jee 空间命名,可以有效地简化 Java EE 资源的引用,以下片段示例使用 jee 命名空间引用 JNDI 数据源的位置:
 
<beans ...>
    <jee:jndi-lookup id="dataSorce" jndi-name="java:comp/env/jdbc/bbt" />
</beans>


使用属性文件配置数据源

以上配置 DBCP 和 C3P0 数据源时,是将数据源连接参数硬编码到bean配置文件中,在实际项目中,为了维护连接数据的安全性和方便修改,往往会将这些连接数据存放到一个配置文件中,然后通过 SpEL 调用该配置文件的参数到bean配置文件;
将 C3P0 数据源的连接参数存放到 jdbc.properties 
 
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql//127.0.0.1:3306/sampleDB
jdbc.userName=root
jdbc.password=1234
配置数据源bean片段
 
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destory-method="close"
      p:dirverClass="#{jdbc.driverClass}"
      p:jdbcUrl="#{jdbc.url}"
      p:username="#{userName}"
      p:password="#{passowrd}" />


解决MySQL的“8小时问题”

如果使用数据库为MySQL,当数据源配置不当时,很容易发生经典的 ”8小时问题“,原因是 MySQL 默认情况如果发现一个连接的空闲时间超过8个小时,则会在数据库端自动关闭该连接,而数据源不知道该数据源连接已经被数据库关闭了,当这个无用的连接返回给某个 DAO 时,DAO 会报无法获取 Connection 的异常;

在采用 DBCP 或 C3P0 的默认配置下,由于 testOnBorrow 属性的默认值为 true,即数据源在将连接交给 DAO 前,都会先检查该连接是否完好,所以并不会发生 ”8 小时问题“;但是这种默认的配置由于每次提交连接给DAO时都会检测连接的有效性,在高并发的应用中会带来性能问题;

一个推荐的高效解决方式如下:
设置 testOnBorrow 为 false,testWhileIdle 为 true,根据实际情况设置 timeBetweenEvictionRunsMills 的值;
这时,DBCP 和 C3P0 将会通过一个后台线程定时对空闲连接进行检测,当发现无用空闲连接时,就会将他们清除掉,只要 timeBetweenEvictionRunsMills 小于8小时,就可以避免 MySQL 的 ”8小时问题“;



 


相关文章:

  • 2021-10-30
  • 2021-09-01
  • 2021-06-03
  • 2021-06-17
  • 2022-01-04
  • 2021-11-28
猜你喜欢
  • 2022-12-23
  • 2021-10-15
  • 2021-12-06
  • 2021-12-08
  • 2022-12-23
  • 2021-11-19
相关资源
相似解决方案