Spring征服数据库
来源:互联网 发布:java开发订单系统 编辑:程序博客网 时间:2024/04/29 21:04
DAO:数据访问对象(data access object)的缩写。
如何你曾经编写过JDBC代码,你肯定会意识到如果不强制捕获SQLException,你几乎不能使用JDBC做任何事情。SQLException表示在尝试访问数据库时出现了问题,但是这个异常却没有告诉你哪里出错了以及如何进行处理。
可能导致抛出SQLException的常见问题包括:
1、应用程序无法连接数据库。
2、要执行的查询有语法错误。
3、查询中所使用的表和(或)列不存在。
4、试图插入或更新的数据违反了数据库的完整性约束。
它不是对每种可能的问题都会有不通的异常类型。而都是抛出SQLException。
一方面,JDBC的异常体系过于简单了---实际上,它算不上一个体系。另一方面,Hibernate的异常体系是其本身所独有的。我们需要的是,数据访问异常要具有描述性而且又与特定的持久化框架无关。
Spring几乎为读取和写入数据库的所有错误都提供了异常。Spring的数据访问异常很多。尽管Spring的异常体系比JDBC简单的SQLException丰富的多,但它没有与特定的持久化方式相关联。这意味着我们可以使用Spring抛出一致的异常,而不用关心所选择持久化方案。
Spring的异常大多继承自DataAccessException。这个异常的特殊指出在于它是一个非检查型异常。说白了不用写try catch。这把是否捕获异常的权利留给了开发人员。
Spring提供的数据访问模版,分别适用于不通的持久化机制。
下面分别是模版类和它的用途:
jca.cci.core.CciTemplate : JCA CCI连接
jdbc.core.JdbcTemplate : JDBC连接
jdbc.core.namedparam.NamedParameterJdbcTemplate : 支持命名参数的JDBC连接
jdbc.core.simple.SimpleJdbcTemplate : 通过java5简化后的JDBC连接
orm.hibernate.HibernateTemplate : Hibernate 2.x的Session
orm.hibernate3.HibernateTemplate : Hibernate 3.x的Session
orm.ibatis.SqlMapClientTemplate : iBATIS SqlMap客户端
orm.jdo.JdoTemplate : Java数据对象实现
orm.jpa.JpaTemplate : Java持久化API的实体管理器
配置数据源
1、使用JNDI数据源
Spring应用程序经常部署在Java EE应用服务器中,如WebSphere、JBoss或者像Tomcat这样的Web容器。这些服务器允许你配置通过JNDI获取数据源。这种配置的好处在于数据源完全可以在应用程序之外进行管理,这样应用程序只需在访问数据库的时候查找数据源就可以了。
使用<jee:jndi-lookup>元素装配到Spring中。
<!-- 其中jndi-name属性用于指定JDDI中资源的名称。如果只设置了jndi-name属性,那么就会根据指定的名称查找数据源。但是,如果应用程序运行在Java应用程序服务器中,则需要将resource-ref属性设置为true,这样给定的jndi-name将会自动添加java:comp/env/前缀 --><jee:jndi-lookup jndi-name="/jdbc/SpitterDS" id="dataSource" resource-ref="true" />
2、使用数据源连接池
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="org.hsqldb.jdbcDriver" /><property name="url" value="jdbc:hsqldb:hsql://localhost/spitter.spitter" /><property name="username" value="sa" /><property name="password" value="" /><property name="initialSize" value="5" /><property name="maxActive" value="10" /></bean>
前4个属性是配置BasicDataSource所必需的。下面列出了另外的最有用的一些属性。
initialSize:池启动时创建的连接数量。
maxActive:同一时间可从池中分配的最多连接数。如果设置为0,表示无限制。
maxIdle:池里不会被释放的最多空闲连接数。如果设置为0,则表示无限制。
maxOpenPreparedStatements:在同一时间能够从语句池中分配的预处理语句的最大数量。如果设置为0,表示无限制。
maxWait:在抛出异常之前,池等待连接回收的最大时间(当没有可用连接时)。如果设置为-1,表示无限等待。
minEvictableIdleTimeMillis:连接在池中保持空闲而不回收的最大时间。
minIdle:在不创建新连接的情况下,池中保持空闲的最小连接数。
poolPreparedStatements:是否对预处理语句进行池处理(布尔值)
3、基于JDBC驱动的数据源
在Spring中,通过JDBC驱动定义数据源是最简单的配置方式。Spring提供了两种数据源对象。
DriverManagerDataSource:在每个连接请求时都会返回一个新建的连接。与DBCP的BasicDataSource不同,由DriverManagerDataSource提供的连接兵没有进行池化管理。
SingleConnectionDataSource:在每个连接请求时都会返回同一个连接。尽管SingleConnectionDataSource不是严格意义上的连接池数据源,但是你可以将其视为只有一个连接的池。
以上两个数据源的配置与BasicDataSource的配置类似:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="org.hsqldb.jdbcDriver" /><property name="url" value="jdbc:hsqldb:hsql://localhost/spitter.spitter" /><property name="username" value="sa" /><property name="password" value="" /></bean>
唯一的区别在于DriverManagerDataSource和SingleConnectionDataSource都没有提供连接池功能,所以没有可配置的池相关的属性。
SingleConnectionDataSource有且只有一个数据库连接,所以不适用于多线程的应用程序。尽管DriverManagerDataSource支持多线程,但是在每次请求连接时都会创建新连接,这是以性能为代价的。鉴于以上的这些限制,我强烈建议应该使用数据源连接池。
使用JDBC模版
Spring为JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码,让我们只需编写从数据库读写数据的必须代码。
Spring将数据访问的样板式代码提取到模版类中。Spring为JDBC提供了3个模版类供使用。
1、JdbcTemplate:最基本的Spring的JDBC模版,这个模版支持最简答你的JDBC数据库访问功能以及简单的索引参数。
2、NamedParameterJdbcTemplate:使用该模版类执行查询时,可以将查询值以命名参数的形式绑定到SQL中,而不是使用简单的索引参数。
3、SImpleJdbcTemplate:该模版类利用Java5的一些特性,例如自动装箱、泛型以及可变参数列表来简化JDBC模版的使用。
使用SImpleJdbcTemplate访问数据
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate"><constructor-arg ref="dataSource"></constructor-arg></bean>
现在,可以将jdbcTemplate装配到DAO中兵使用了SImpleJdbcTemplate:
public class JdbcSpitterDAO implements SpitterDAO {private SimpleJdbcTemplate jdbcTemplate ;public void setJdbcTemplate(SimpleJdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate ;}}
你还需要装配JdbcSpitterDAO的jdbcTemplate属性,如下:
<bean id="spitterDao" class="com.habuma.spitter.persistence.SimpleJdbcTemplateSpitterDao"><property name="jdbcTemplate" ref="jdbcTemplate" /></bean>
下面是基于SimpleJdbcTemplate的addSpitter()方法。
public void addSpitter(Spitter spitter) {jdbcTemplate.update(SQL_INSERT_SPITTER, spitter.getUsername(),spitter.getPassword(),spitter.getFullName(),spitter.getEmail(),spitter.isUpdateByEmail()) ;spitter.setId(queryForIdentity()) ;}
使用JdbcTemplate也简化了数据读取操作。下面是个新方法,在这个方法中使用SimpleJdbcTemplate回调将结果集映射成域对象。
public Spitter getSpitterById(long id) {return jdbcTemplate.queryForObject(SQL_SELECT_SPITTER_BY_ID, new ParameterizedRowMapper<Spitter>() {@Overridepublic Spitter mapRow(ResultSet rs, int rowNum)throws SQLException {Spitter spitter = new Spitter() ;spitter.setId(rs.getLong(1)) ;spitter.setUsername(rs,getString(2)) ;spitter.setPassword(rs.getString(3)) ;spitter.setFullName(rs.getString(4)) ;return spitter ;return null;}}, id) ;}
在getSpitterById()方法中使用了SimpleJdbcTemplate的queryForObject()方法来从数据库查询Spitter。queryForObject()方法有3个参数:
1、String,包含了要从数据库中查找数据的SQL。
2、parameterizedRowMapper对象,用来从ResultSet中提取值并构建域对象
3、可变参数列表,列出了要绑定到查询上的索引参数值。
使用命名参数
在上面的addSpitter()方法使用了索引参数。这意味着我们需要留意查询中参数的顺序,而在将值传递给update()方法的时候要保持正确的顺序。如果在修改SQL时更改了参数的顺序,那么我们还需要修改参数值的顺序。
除了这种方法之外,我们还可以使用命名参数。命名参数可以赋予SQL中的每个参数一个明确的名字,在绑定值到查询语句的时候就通过该名字来引用参数。例如:
private static final String SQL_INSERT_SPITTER = "insert into spitter(username, password, fullname) " + "values (:username, :password, :fullname)" ;
使用命名参数查询,绑定值的顺序就不重要了,我们可以按照名字来绑定值。如果查询语句发生了变化导致参数的顺序域之前不一致,我们不需要修改绑定的代码。
public void addSpitter(Spitter spitter) {Map<String, Object> params = new HashMap<String, Object>() ;params.put("username", spitter.getUserName()) ;params.put("password", spitter.getPassword()) ;params.put("fullname", spitter.getFullName()) ;jdbcTemplate.update(SQL_INSERT_SPITTER, params) ;spitter.setId(queryForIdentity()) ;}
使用SPring 的JDBC DAO支持类
对于应用程序中的每一个JDBC DAO类,我们都需要添加一个SimpleJdbcTemplate属性以及对应的setter方法,并确保将SimpleJdbcTemplate Bean装配到每个DAO的SimpleJdbcTemplate属性中。如果应用程序中只有一个DAO,这并不算什么问题,但是如果有多个DAO的话,这就会产生大量的重复工作。
一种可行的解决方案就是为所有的DAO创建一个通用的父类,在其中会有SimpleJdbcTemplate属性。然后让所有的DAO类继承这个类兵使用父类的SimpleJdbcTemplate进行访问。
Spring提供了内置的基类。(JdbcDaoSupport、SimpleJdbcDaoSupport和NamedParameterJdbcDaoSupported)
下面是例子:
public class JdbcSpitterDao extends SimpleJdbcDaoSupport implements SpitterDao{...}
SimpleJdbcDaoSupport通过getSimpleJdbcTemplate()能够便捷地访问SimpleJdbcTemplate。例如,addSpitter()方法可以这样改写:
public void addSpitter(Spitter spitter) {getSimpleJdbcTemplate().update(SQL_INSERT_SPITTER, spitter.getUserName(),spitter.getPassword(),spitter.getFUllName(),spitter.getEmail(),spitter.isUpdateByEmail()) ;spitter.setId(queryForIdentity()) ;}
在Spring中继承Hibernate
在使用过jdbc后,我们还需要一些复杂的特性:
1、延迟加载:我们可以只抓去需要的数据。
2、预先抓取:这与延迟加载是相对的,借助于预先抓去,我们可以使用一个查询获取完整的关联对象。如果需要PurchaseOrder及其关联的LineItem对象,预先抓去的功能可以在一个操作中将它们全部从数据库中提取出来,这节省了多次查询的成本。
3、级联:有时,更改数据库中的表会同时修改其他表。
SPring对多个持久化框架都提供了支持,包括Hibernate、iBATIS、JAVA数据对象(Java Data Objects,JDO)以及java持久化API。
与Spring对JDBC的支持那样,Spring对ORM框架的支持提供了与这些框架的集成点以及一些附加的服务,如下所示:
1、Spring声明式事务的集成支持
2、透明的异常处理
3、线程安全的、轻量级的模版类
4、DAO支持类
5、资源管理
声明Hibernate的Session工厂
使用Hibernate的主要接口是org.hibernate.Session。Session接口提供了基本的数据访问功能,如保存、更新、删除以及从数据库加载对象的功能。通过Hibernate的Session接口,应用程序的DAO能够满足所有的持久化需求。
获取Hibernate Session对象的标准方式是借助于Hibernate的SessionFactory接口的实现类。除了一些其他的任务,SessionFactory主要负责Hibernate Session的打开、关闭以及管理。
1、XML配置
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="mappingResources"><list><value>Spitter.hbm.xml</value></list></property><property name="hibernateProperties"><props><prop key="dialect">org.hibernate.dialect.HSQLDialect</prop></props></property></bean>
2、注解配置
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="packagesToScan" value="com.habuma.spitter.domain" /><property name="hibernateProperties"><props><prop key="dialect">org.hibernate.dialect.HSQLDialect</prop></props></property></bean>
就像在LocalSessionFactoryBean中那样,dataSource和hibernateProperties属性声明了从哪里获取数据库连接以及要使用哪一种数据库。
这里不再列出Hibernate配置文件,而是使用packagesToScan属性告诉Spring扫描一个或多个包以查找域类,这些类通过注解方式表明要使用Hibernate进行持久化。使用JPA的@Entity或@MappedSuperclass注解以及Hibernate的@Entity注解进行标注的类都会包含在内。
如果愿意,我们还可以通过使用annotatedClassed属性来将应用程序中所有的持久化类以全限定名的方式明确列出:
<property name="annotatedClassed"><list><value>com.habuma.spitter.domain.Spitter</value><value>com.habuma.spitter.domain.Spittle</value></list></property>
annotatedClassed属性对于准确指定少量的域类是不错的选择。如果你有很多的域类且不想将其全部列出。或者你想自由地添加或溢出域类而不想修改Spring配置的话,则使用packagesToScan属性更合适。
构建不依赖于Spring的Hibernate代码
import org.hibernate.Session;import org.hibernate.SessionFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;@Repositorypublic class HibernateSpitterDao implements SpitterDao{private SessionFactory sessionFactory ;@Autowiredpublic HibernateSpitterDao(SessionFactory sessionFactory) {this.sessionFactory = sessionFactory ;}private Session currentSession() {return sessionFactory.getCurrentSession() ;}public void addSpitter(Spitter spitter) {currentSession().save(spitter) ;}public Spitter getSpitterById(long id) {return (Spitter)currentSession().get(Spitter.class, id) ;}public void saveSpitter(Spitter spitter) {currentSession().update(spitter);}}
我们在类上使用了@Repository注解,这会为我们做两件事情。首先,@Repository是Spring的另一种构造型注解,它能够像其他注解一样被Spring的<context:component-scan>所扫描到。这样就不必明确声明HibernateSpitterDao Bean了,只需在<context:component-scan>配置即可。
除了帮助简化XML配置以外,@Repository还有另外一个用处。让我们回想一下模版类,它有一项任务就是捕获平台相关的异常,然后以Spring的非检查型异常形式重新抛出。如果我们使用Hibernate上下文Session而不是Hibernate模版,那么异常转换会怎么处理呢?
为了给不使用模版的Hibernate DAO添加异常转换功能,我们只需在Spring应用上下文中添加一个PersistenceExceptionTranslationPostProcessorBean:
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
PersistenceExceptionTranslationPostProcessor是一个Bean的后置处理程序,它会在所有拥有@Repository注解的类上添加一个通知器(advisor),这样就会捕获任何平台相关的异常并以Spring的非检查型数据访问异常的形式重新抛出。
Spring与Java持久化API
配置实体管理器工厂
简单来说,基于JPA的应用程序使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实体管理器:
1、应用程序管理类型:当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开或关闭实体管理器并在事务中对其进行控制。这种方式的实体管理器适合于不运行在Java EE容器中的独立应用程序。
2、容器管理类型:实体管理器由Java EE创建和管理。应用程序根本不与实体管理器工厂打交道。相反,实体管理器直接通过注入或JNDI来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适合用于Java EE容器,在这种情况下会希望在persistence.xml指定的JPA配置之外保持一些自己对JPA的控制。
它们两个的区别在于EntityManager的创建和管理方式。应用程序管理类型的EntityManager是由EntityManagerFactory创建的。而后者是通过PersistenceProvider的createEntityManagerFactory()方法得到的。与此相对,容器管理类型的entityManagerFactory是通过PersistenceProvider的createContainerEntityManagerFactory()方法获得的。
在容器管理的场景下,SPring会担当容器的角色。
这两种实体管理器工厂分别由对应的Spring工厂Bean创建的:
1、LocalEntityManagerFactoryBean生成应用程序管理类型的EntityManagerFactory。
2、LocalContainerEntityManagerFactoryBean生成容器管理类型的EntityManagerFactory。
使用应用程序管理类型的JPA
对于应用程序管理类型的实体管理器工厂来说,它绝大部分配置文件来源于一个名叫persistence.xml的配置文件。这个文件必须位于类路径下的META-INF目录下。
persistence.xml的作用在于定义一个或多个持久化单元。持久化单元是同一个数据源下的一个或多个持久化类。简单来讲,persistence.xml列出了一个或多个的持久化类以及一些其他的配置,如数据源和基于XML的配置文件。以下是一个典型的persistence.xml文件,它用于Spitter应用程序。
<persistence xmlns="http://java.sun.com/xml/ns/persistence"version="1.0"><persistence-unit name="spitterPU"><class>com.habuma.spitter.domain.Spitter</class><class>com.habuma.spitter.domain.Spittle</class><properties><property name="toplink.jdbc.driver" value="org.hsqldb.jdbcDriver" /><property name="toplink.jdbc.url" value="jdbc:hsqldb:hsql://localhost/spitter/spitter" /><property name="toplink.jdbc.user" value="sa" /><property name="toplink.jdbc.password" value="" /></properties></persistence-unit></persistence>
因为在persistence.xml文件中包含了大量的配置信息,所以在Spring中需要配置的就很少了。可以通过以下的<bean>元素在Spring中声明LocalEntityManagerFactoryBean:
<bean id="emf" class="org.springframework.orm.jpa.LocalEntityFactoryBean"><property name="persistenceUnitName" value="spitterPU" /></bean>
赋给persistenceUnitName属性的值就是persistence.xml中持久化单元的名称。
使用容器管理类型的JPA
容器管理的JPA采取了一种不同的方式。当在容器中运行时,可以使用容器提供的信息来生成EntityManagerFactory。
你可以将数据源信息配置在Spring应用上下文中,而不是在persistence.xml中了。例如,下面的<bean>声明展现了在Spring中如何使用LocalContainerEntityManagerFactoryBean来配置容器管理类型的JPA。
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><property name="dataSource" ref="dataSource" /><property name="jpaVendorAdapter" ref="jpaVendorAdapter" /></bean>
jpaVendorAdapter属性用于指明所使用的是哪一个厂商的JPA实现。Spring提供了多个JPA厂商适配器:
1、EclipseLinkJpaVendorAdapter
2、HibernateJpaVendorAdapter
3、OpenJpaVendorAdapter
4、TopLinkJpaVendorAdapter
- Spring : 征服数据库 (三)
- Spring征服数据库
- Spring : 征服数据库(一)
- Spring : 征服数据库 (二)
- Spring : 征服数据库 (四)
- Spring和数据库连接 --- 征服数据库jdbc
- Spring框架(五)—— 征服数据库
- Spring实战读书笔记 第五章 征服数据库
- [学习笔记]spring实战-征服数据库
- spring in action-征服数据库(一)
- spring(10)通过spring 和 JDBC征服数据库
- Spring学习笔记之通过Spring和JDBC征服数据库
- Spring in Action 学习笔记—第四章 征服数据库
- Spring in Action(第五章 征服数据库)学习笔记
- 第10章 通过Spring和JDBC征服 数据库
- 征服数据库 --- 集合hibernate
- (笔记)Spring实战_征服数据库(3)_在Spring中使用JDBC
- (笔记)Spring实战_征服数据库(4)_在Spring中集成Hibernate
- 《数据结构)第一章 同学提问第111到135楼参考答案
- W: GPG 错误 没有公钥,无法验证 签名
- redis的配置文件redis.conf常见配置
- 自我发现,找到适合自己的职位
- IOS 调试
- Spring征服数据库
- 关于学习android中v4包中PagerAdapter实现引导页效果
- 【转】使用GDB调试程序详细说明
- Google Dremel 原理 - 如何能3秒分析1PB
- android学习笔记34--------------有用代码集(不断更新)
- WWDC 2013 Session笔记 - UIKit Dynamics入门
- MySQL索引类型一览 让MySQL高效运行起来
- UITextField小结
- linux下安装eclipse