Spring 作为一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,主要负责技术整合,那么Spring是如何整合数据访问的呢?下面就让我们一起来探讨,有不对的地方敬请指教。
一、Spring 提供了编写 DAO 的支持类
1、DaoSupport 类: JdbcDaoSupport、 HibernateDaoSupport,自己写的 DAO 按使用的访问技术,有选择的继承它们。
2、Template 类: JdbcTemplate、 HibernateTemplate,封装了通用操作,如:增删改查。特殊操作,如:分页查询。
3、继承 DaoSupport 类后,就可通过 getJdbcTemplate()、 getHibernateTemplate()方法获得对应的 Template 类对象,即可进行通用操作:
(1)update():实现更新。
(2)query():实现查询多行记录。
(3)queryForObject():实现查询单行记录。
(4)queryForInt():实现查询单个 int 值。
4、 将一条记录转换成一个实体对象,需要实现 Spring 提供的 RowMapper 接口(将实体与记录间的转换写在它的实现类中),因为 Spring 提供的 Template 对象中的查询方法 query()有 RowMapper 类型的参数。
二、Spring 提供了声明式事务管理方法
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。 Spring事务管理器的接口org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。基于 AOP 配置实现,不需要写 Java 代码,加注解标签即可。
Spring 中常用的事务类型:
1、REQUIRED: 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是默认值。
2、SUPPORTS: 支持当前事务,如果当前没有事务,就以非事务方式执行。
3、MANDATORY: 支持当前事务,如果当前没有事务,就抛出异常。
4、REQUIRES_NEW: 新建事务,如果当前存在事务,把当前事务挂起。
5、NOT_SUPPORTED: 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6、NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。
7、NESTED: 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED 类似的操作。拥有多个可以回滚的保存点,内部回滚不会对外部事务产生影响。只对 DataSourceTransactionManager 有效。
三、Spring对JDBC的支持实例
1、新建一个工程,引入 Spring 开发包( IoC 和 AOP 开发包)和配置文件
2、引入JDBC技术相关的开发包(驱动包)
3、根据要操作的表,编写对应的实体类。
4、编写DAO接口TestDAO和实现类 JdbcTestDAO(实现类继承 JdbcDaoSupport,并使用其提供的 getJdbcTemplate 对象实现增删改查操作)
(1) TestDAO 接口
public test findById(int id);
public List
(2) JdbcTestDAO 实现类
public class JdbcTestDAO extends JdbcDaoSupport implements TestDAO{
public Test findById(int id) {
String sql="select * from test where ID=?";
Object[] params={id};
RowMapper mapper=new TestRowMapper();
Test test=(Test)getJdbcTemplate().queryForObject(sql, params,mapper);
return test; }
public List
String sql="select * from test";
/** 将一条记录转换成一个 Test 对象,需要实现 Spring 提供的 RowMapper 接口 */
RowMapper mapper=new TestRowMapper();
List
return list; }
}
(3) 在 org.audTest.entity 包中创建 TestRowMapper 类
public class TestRowMapper implements RowMapper{//实现 RowMapper 接口
/** rs:结果集。 index:当前记录的索引 。 Object:返回实体对象。 */
public Object mapRow(ResultSet rs, int index) throws SQLException {
Test test = new Test();
test.setId(rs.getInt("ID"));
Test.setName(rs.getString("NAME"));
return test;
}
}
5、将 DAO 组件交给 Spring 容器,在 applicationContext.xml 中进行相关配置
(1)定义 DAO 组件的
(2) 需要 DAO 的 Bean 注入一个 dataSource 对象。 dataSource 对象采用一个连接池构建(此处使用 dbcp 连接池),先引入 dbcp 连接池开发包( commons-pool.jar、 commons-dbcp-1.2.2.jar、commons-collections-3.1.jar),再定义 dataSource 对象的
6、创建 TestJdbcTestDAO 类,用于测试 xml 配置,可正常执行
@Test
public void testFindAll() {
//测试基于 xml 配置方法
String conf="/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(conf);
TestDAO TestDAO=(TestDAO)ac.getBean("TestDAO");
List
for(Test c:list){
System.out.println(c.getId()+" "+c.getName());
}
System.out.println("findById: "+TestDAO.findById(1).getName());
}
7、使用注解配置,保留 5 中的连接资源 MyDataSource,而 Bean 组件 TestDAO 删除,并添加开启组件扫描的配置
8、在 JdbcTestDAO 中添加注解
@Repository //id 值默认为类名首字母小写
@Scope("prototype") //设置非单例模式
public class JdbcTestDAO extends JdbcDaoSupport implements TestDAO{
@Resource //将容器中的 myDataSource 按类型匹配注入
/** 虽然继承了 JdbcDaoSupport,但我们无法在别人的代码中添加注解,所以我们
添加一个 set 方法, 注意名字别用 setDataSource!因为 JdbcDaoSupport 有同名的 set 方法,
且是 final 修饰的,所以需要稍微改变一下。 */
public void setMyDataSource(DataSource ds){
super.setDataSource(ds);//将注入的 dataSource 给 DaoSupport 注入 }
9、在 TestJdbcTestDAO 类添加方法,用于测试注解配置,可正常执行
@Test
public void testFindAllByAnnotation() {
//测试基于注解配置方法
String conf="/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(conf);
TestDAO TestDAO=(TestDAO)ac.getBean("jdbcTestDAO");
List
for(Test c:list){ System.out.println(c.getId()+" "+c.getName()); }
System.out.println("findById: "+TestDAO.findById(1).getName()); }
10、优化,当大量 Bean 组件需要采取注解配置时,每个 Bean 都要写 set 方法注入 dataSource连接资源,所以比较麻烦,可采取继承方式:
(1) 新建 JdbcBaseDAO 类,并继承 JdbcDaoSupport,把 set 方法写入
public class JdbcBaseDAO extends JdbcDaoSupport {
@Resource //将容器中的 myDataSource 按类型匹配注入
public void setMyDataSource(DataSource ds){//注意名字,详见8
super.setDataSource(ds); } }
(2) 删除8中JdbcTestDAOset的 set 方法及其前面的注解,并继承 JdbcBaseDAO
public class JdbcTestDAO extends JdbcBaseDAO implements TestDAO{ …… }
四、连接池优点
1、增强数据访问的稳定性。
2、连接池可以将连接数控制在安全的范围内。
3、连接池中的连接对象始终与数据库保持联通状态,它的 close 方法被重写,不是真正的关闭,而是把连接又放回池中,避免了重复的新建连接和释放连接过程。
五、Spring对Hibernate的支持实例
1、新建一个工程,引入 Spring 开发包( IoC 和 AOP 开发包)和配置文件
2、引入 Hibernate 相关的开发包( Hibernate 开发包+驱动)
3、编写实体类和 hbm.xml 映射描述文件
4、编写 DAO 接口和 HibernateTestDAO 实现类(实现类继承 HibernateDaoSupport,并使用其提供的 HibernateTemplate 对象实现增删改查操作)
5、将 DAO 组件交给 Spring 容器管理,在 applicationContext.xml 中进行相关配置
6、在 applicationContext.xml 中配置 sessionFactory 资源(相当于 Hibernate 的主配置)
7、在 applicationContext.xml 中配置 dataSource 数据库连接资源dataSource 对象采用一个连接池构建(此处使用 dbcp 连接池),先引入 dbcp 连接池开发包
property name="url" value="jdbc:mysql://localhost:3306/web?useUnicode=true&characterEncoding=UTF-8">
8、创建 TestHibernateTestDAO 类,用于测试 xml 配置
9、使用注解配置,新建 applicationContext-annotation.xml 配置文件,并添加开启组件
扫描的配置
10、在 HibernateTestDAO 中添加注解
@Repository("HibernateTestDAO")
@Scope("prototype")
public class HibernateTestDAO extends HibernateDaoSupport implements TestDAO {
@Resource //setSessionFactory 名字用不了是 final
public void setMySessionFactory(SessionFactory sf){
super.setSessionFactory(sf);//将注入的 sessionFactory 给 HibernateDaoSupport 传入
}
11、在 TestHibernateTestDAO 类添加方法,用于测试注解配置,可正常执行
12、在 TestHibernateTestDAO 类添加方法,用于测试查询