Spring在持久化上做出了一个统一的模型,目的是为了简化持久化的开发,使得数据访问层和持久化方案的选择相互独立。
统一了数据访问异常:
传统的JDBC异常分类比较薄弱,并且都为检查型异常,在程序员对数据库的操作过程中,需要强制的去捕获SQLException,第一是工作比较繁琐,第二个就算捕获了之后其实际意义也不大,并且SQLException包含的异常问题不能够准确的进行表达,有可能是连接异常,有可能是数据访问的其他问题,spring在此基础上统一了数据访问异常,提供更加丰富的异常管理,并且所有异常都会运行期异常,不需要用户做出捕获动作,需要进行捕获时,由程序员自行决定,无论是选择何种持久化方案,在spring的管理下,异常都可以得到统一,这样从异常的角度完成了数据访问层和持久化方案选择的独立。
数据访问模板:
spring提供数据访问模板,利用模板方法模式以及回调来简化数据访问层的代码编写,使得程序员在数据访问代码编写时候,关注点只关注数据访问的核心逻辑,对于连接的打开,关闭等操作都进行了忽略,大大的加快了数据访问的开发效率,也就是说spring提供模板,减少了系统当中的样板代码的编写
常用的模板:
模板类 | 用途 |
jca.cci.core.CciTemplate | JCA CCI连接 |
jdbc.core.JdbcTemplate | JDBC连接 |
jdbc.core.namedparam.NamedParameterJdbcTemplate | 支持命名参数的Jdbc连接 |
jdbc.core.simple.SimpleJdbcTemplate | 通过Java 5简化后的JDBC连接 |
orm.hibernate.HibernateTemplate | hibernate2.x session |
orm.hibernate3.HibernateTemplate | hibernate3.x session |
orm.ibatis.SqlMapClientTemplate | ibatis sqlMap客户端 |
orm.jdo.jdoTemplate | Java数据对象实现 |
orm.jpa.jpaTemplate | Java持久化API管理器 |
提供DAO支持类:
DAO支持类与spring提供的模板如出一辙,如果要使用模板,则可以继承于spring DAO的支持类,之后很方便的获取到DAO支持类提供的模板,进行数据访问操作。上述模板介绍中每一个模板都对应一个DAO支持类,用于更为方便的在spring中获取到模板。
配置数据源:
在spring配置数据源有三种方式:
通过JDBC驱动定义的数据源 |
JNDI查找数据源 |
连接池的数据源 |
JDNI数据源:
增加命名空间:
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"
XML配置:
<jee:jndi-lookup jndi-name="jdbc/DS" resource-ref="true" />
jndi-name用于指定JNDI查找路径,如果是在JAVA应用服务器中需要配置resource-ref为true,这样会自动添加上java:comp/env/前缀
数据库连接池:
数据库连接池的选择很多,通常会有prooxy,c3p9,dbcp等等,spring本身没有提高数据库连接池的实现,但是可以有效的与第三方数据库连接池进行集成
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/hello?useUnicode=true&charact erEncoding=utf8"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> <property name="initialSize" value="5"></property> <property name="maxActive" value="10"></property> </bean>
基于JDBC驱动的数据源:
spring提供了两个最简单的JDBC数据源:
DriverMangerDatasource:每个连接请求返回一个新建的连接,但是没有池化管理
SingleConnectionDatasource:每次返回都用同一个连接
应用一个连接的SingleConnectionDatasource不适用于多线程的应用程序,而每次请求都会创建的DriverManager会在程序运行中出现性能问题,所以强烈建议在生产环境中使用数据库连接池
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/hello?useUnicode=true&charact erEncoding=utf8"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean>
在Spring中使用JDBC:
spring提供三种JdbcTemplate用于对JDBC的访问,JdbcTemplate,SimpleJdbcTemplate,NamedParameterJdbcTemplate,其中SimpleteJdbcTemplate在3.1中已经被废弃,原因是JdbcDaoSupport 或NamedParameterJdbcDaoSupport已经提供了其所有功能,所以要使用SimpleJdbcTemplate继承于JdbcDaoSupport即可
JdbcTemplate:最基本的Jdbc模板,提供基本的数据库访问
SimpleJdbcTemplate:利用java 5的一些特性,如自动装箱,泛型,以及可变参数来简化JDBC模板使用
NamedParameterJdbcTemplate:查询时候,可以使用命名参数绑定到sql中,而不是只是简单的索引参数
JdbcTemplate配置:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>SimpleJdbcTemplate配置:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate"> <constructor-arg ref="dataSource"></constructor-arg> </bean>NamedParameterJdbcTemplate配置:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcT emplate"> <constructor-arg ref="dataSource" ></constructor-arg> </bean>使用:
public void addBand(Band band){
String sql = "insert into t_band(id, name), values(?,?)";
getJdbcTemplate().update(sql, band.getId(), band.getName());
}
public Band findBandById(String id){
String sql = "select id,name from t_band where id = ?";
return getJdbcTemplate().queryForObject(sql, new ParameterizedRowMapper<Band>() {
@Override
public Band mapRow(ResultSet rs, int rowNum) throws SQLException {
Band band = new Band();
band.setId(rs.getString(1));
band.setName(rs.getString(2));
return band;
}
}, id);
}
有命名参数绑定的sql,使用NamedParameterJdbcTemplate,该例中JdbcTemplate来自于NamedParameterJdbcDaoSupport:
public Band findBandById(String id){
String sql = "select id,name from t_band where id = :id";
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", id);
return getJdbcTemplate().queryForObject(sql, new ParameterizedRowMapper<Band>() {
@Override
public Band mapRow(ResultSet rs, int rowNum) throws SQLException {
Band band = new Band();
band.setId(rs.getString(1));
band.setName(rs.getString(2));
return band;
}
}, params);
}
Spring集成HIbernate:
LocationSessionFactory(hibernate4)的配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="mappingResources"> <list> <value>band.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="dialect">org.hibernate.dialect.MySQL5Dialect</prop> </props> </property> </bean>
基于注解扫描@Entity
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="packagesToScan" value="org.robbie.test"></property> <property name="hibernateProperties"> <props> <prop key="dialect">org.hibernate.dialect.MySQL5Dialect</prop> </props> </property> </bean>
在Spring中使用hibernate:
package org.robbie.test.spring.beans;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class MyDao{
@Autowired
private SessionFactory sessionFactory;
private Session getCurrentSession(){
return sessionFactory.openSession();
}
public void insert(){
Session session = getCurrentSession();
Transaction transaction = session.getTransaction();
transaction.begin();
try {
MyDomain domain = new MyDomain();
domain.setId("4");
domain.setName("robbie");
session.save(domain);
} catch (Exception e) {
transaction.rollback();
System.out.println(e);
}
transaction.commit();
}
}
通过注入的方式,把SessionFactory装配进来,调用API进行使用,类级别的注解@Repository有两个作用,第一个作用是作为Spring的组件使用,会被自动检测到容器当中,第二个是如果配置了spring全局异常处理,那么在标注了该注解的类中的方法都会捕获sql异常,并统一转换成与持久化方案无关的spring数据访问异常(运行期异常),使得DAO和持久化选择方式脱离,程序更容易管理,并减少代码量。
Spring统一持久层异常的配置:
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
如果是hibernate4还需要加入以下配置(在JTA事务中):
<bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>
Spring集成JPA:
JPA的实体管理工厂有两个:
LocalEntityManagerFactoryBean:是应用程序管理类型的工厂,一般会在一个独立的应用程序中使用
Local,由用户程序直接请求工厂,创建实体管理器,需要手动打开或关闭事务,单独进行配置
LocalContainerManagerFactoryBean:是容器管理类型的工厂,用户程序不会直接跟此工厂打交道,而是通过容器进行注入,创建实体管理器,事务受容器管理,在spring中进行配置
应用程序管理类型的工厂配置:
创建persistence.xml,这个文件必须位于类路径的META-INF目录下
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="unit1"> <class>org.test.Bean1</class> <class>org.test.Bean2</class> <properties> <property name="toplink.jdbc.driver" value="org.hsqldb.jdbcDriver"></property> <property name="toplink.jdbc.url" value="jdbc:hsqldb:hsql://localhost/test"></property> <property name="toplink.jdbc.user">root</property> <property name="toplink.jdbc.password">root</property> </properties> </persistence-unit> </persistence>增加spring的配置:
<bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="unit1"></property>
</bean>
目前为止JPA的配置没有完成,是因为没有配置实现,但是把相关的JPA实现配置信息全部放在persistent.xml上会显得非常的臃肿和不好管理,所以通常情况下在web项目都没有采用这种方式的配置。
在容器管理的实体管理器工厂:
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"></property> </bean> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="MYSQL"></property> <property name="showSql" value="true"></property> <property name="generateDdl" value="true"></property> <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"></property> </bean>JPA的厂商适配器:
EclipseLinkJpaVendorAdapter |
HibernateJpaVendorAdapter |
OpenJapVendorAdaptor |
ToplinkJpaVendorAdaptor |
从JNDI获取实体管理器工厂:
<jee:jndi-lookup id="emf" jndi-name="persistence/unit1" />
编写基于JPA的DAO:
@PersistenceContext
private EntityManager em;
需要用到em的地方通过此种方法进行注入即可。
目前为止,与持久化框架的集成都是采用传统的XML配置,回顾基于JAVA的@Configuration配置,也可以完成,并且更加灵活,至于项目中该采用何种配置方法由用户自己决定。