持久层:所谓“持久层”,也就是在系统逻辑层面上,专著于实现数据持久化的一个相对独立的领域(Domain),是把数据保存到可掉电式存储设备中。持久层是负责向(或者从)一个或者多个数据存储器中存储(或者获取)数据的一组类和组件。大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。

一、DAO的支持

  DAO是数据访问对象(data access object)的缩写,是一个面向对象的数据库接口。对于数据库的存取,spring提供了DAO的支持,可以不用管任何

的底层数据库细节,spring 的一组DAO接口就可以完成所有数据的操作。DAO提供了数据读取和写入到数据库中的一种方式。

  spring没有自己的持久层实现,但是它提供了DAO的支持,可以任意封装任何其他的持久层实现框架。

  服务对象通过接口来访问DAO,优点:

  1.使得服务对象易于测试,因为他们不再与特定的数据访问实现绑定在一起。

  2.数据访问层是以持久化技术无关的方式进行访问的。持久化方式的选择独立于DAO,只有相关的数据访问方法通过接口来进行发布。这样可以实现灵活的设计并使得切换持久化框架对应用程序其他部分所带来的影响最小。

  spring将数据访问过程中固定的和可变的部分明确划分为两个不同的类:模板(template)和回调(callback)。

  spring的模板类处理数据访问的固定部分——事物控制、管理资源以及处理异常。

  spring的回调类处理应用程序相关的数据访问——创建语句、绑定参数以及整理结果集。

(1)举一个传统的DAO例子,首先建立一个用户对象User

package spring.chapter4;

public class User {
private Long id;
private String username;
private String password; public Long getId() {
return id;
}
public void setId(Long id) {
this.id=id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username=username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password=password;
}
}

(2)设计一个操作用户的DAO接口IUserDAO

package spring.chapter4;

public interface IUserDAO {
public void insert(User user);
public void delete(User user);
public void update(User user);
public User find(Long id);
}

(3)写一个IUserDAO的实现类,就是操作数据库的底层代码

package spring.chapter4;

import java.sql.SQLException;

import javax.activation.DataSource;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
import com.mysql.jdbc.StatementImpl; public class UserDAO implements IUserDAO {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource=dataSource;
} public void insert(User user) {
String userName=user.getUsername();
String password=user.getPassword();
Connection conn=null;
java.sql.PreparedStatement stmt=null;
try {
conn=dataSource.getConnection();
stmt=conn.prepareStatement("insert into user(name,password) value(?,?)");
stmt.setString(1, userName);
stmt.setString(2, password);
}catch(SQLException e) {
e.printStackTrace();
}
finally {
if(stmt!=null) {
try {
stmt.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
}
}
//省略其他方法
}

二、数据源的注入

  1.在spring中都是采用IOC(控制反转)方式注入数据源,直接在配置文件中给DAO注入数据源。在spring中不用考虑数据库的类型,均可以使用配置文件来完成数据源的注入,同时支持多种不同的数据源,如JDBC、连接池和JNDI等注入。不管使用声明方式,只要保留一个DataSource的接口就可以进行数据源注入了。

  (4)结合前面的UserDAO,可以写如下配置文件来注入DataSource。(通过jdbc驱动程序定义的数据源)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/news" />
<property name="username" value="root" />
<property name="password" value="******" />
</bean>
<bean id="userDao" class="spring.chapter4.UserDAO">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>

(5)测试代码如下:

package spring.chapter4;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestDAO {
public static void main(String [] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring/chapter4/web.xml");
User user=new User();
user.setUsername("gaochao");
user.setPassword("gaochao");
IUserDAO userDao=(IUserDAO)context.getBean("userDao");
userDao.insert(user); System.out.println("name:"+user.getUsername()+",password:"+user.getPassword());
} }

  2.DBCP连接池注入数据源

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/news" />
<property name="username" value="root" />
<property name="password" value="******" />
</bean>
<bean id="userDao" class="spring.chapter4.UserDAO">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>

  可以看出,只需要修改Bean的class为org.apache.commons.dbcp.BasicDataSource就可以。注意这里设置了一个destroy-method方法,该方法表示在BeanFactory关闭的时候调用close方法关闭BasicDataSource。

  3.JNDI的支持

  与DBCP相比,在进行web开发中,更多的是使用JNDI来连接数据库。这里以Tomcat容器为例,首先在Tomcat\conf目录下找到server.xml中的</Host>前添加context,代码如下:

<!-应用程序的目录是webapp -->
<Context path="webapp" docBase="webapp">
<Resource name="jdbc/news" scope="Shareable" type="javax.sql.DataSource" />
<ResourceParams name="jdbc/news">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<!-数据库的连接URL -->
<parameter>
<name>url</name>
<value>jdbc:mysql://localhost:3306/news</value>
</parameter>
<!- 数据库连接的驱动程序 -->
<parameter>
<name>driverClassName</name>
<value>com.mysql.jdbc.Driver</value>
</parameter>
<!-数据库连接的用户名 -->
<parameter>
<name>username</name>
<value>gaochao</value>
</parameter>
<!-数据库连接的密码 -->
<parameter>
<name>password</name>
<value>*****</value>
</parameter>
<!-等待连接的时间,单位为毫秒,-1为不限制 -->
<parameter>
<name>maxWait</name>
<value>3000</value>
</parameter>
<!-连接池中最少连接数,0为不限制 -->
<parameter>
<name>maxIdle</name>
<value>10</value>
</parameter>
<!-连接池中最多的连接数,0为不限制 -->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
</ResourceParams>
</Context>

  在Tomcat配置好连接池后就可以修改前面的spring配置文件来获取连接池:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="jndiName" value="jdbc/news" />
</bean>
<bean id="userDao" class="spring.chapter4.UserDAO">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>

三、JDBC的支持

  1.Template模式:在父类中定义一个操作中的骨架算法,而将一些用户自定义的逻辑延迟到子类中。示例:加入所有的business方法中都必须进行用户验证、异常捕获和一个业务操作,那么就将用户验证、异常捕获封装到父类中,子类只需要写一些business代码就可以了。父类代码如下:

package spring.chapter4;

public abstract class BusinessTemplate {
public void execute() throws Exception{
validataUser();
try {
business();
doBusiness();
}catch (Error e) {
e.printStackTrace();
}
}
void validataUser() {
System.out.println("验证用户...");
};
void business() {
System.out.println("业务1");
}
public abstract void doBusiness();
}

这里是一个抽象类,有一个execute()方法,在该方法中进行了用户验证、异常捕获和一个业务的执行。在这三项任务结束后执行了doBusiness()方法,同时doBusiness()方法又是一个抽象方法,继承该抽象类就要重写这个抽象方法,在这里定义用户自己的业务,写一个子类如下:

package spring.chapter4;

public class Business extends BusinessTemplate{
public void doBusiness() {
System.out.println("自定义业务");
} }

这里继承类就重写了doBusiness方法,定义一个用户自己的业务,接着写一个测试类如下:

package spring.chapter4;

public class TestTemplate {
public static void main(String[] args) throws Exception {
Business business=new Business();
business.execute();
}
}

这里的Business类调用了父类的execute方法,按execute()方法执行顺序来执行后,运行结果如下:

这里的Business类是BusinessTemplate的一个子类,原本也需要写用户验证和异常捕获等业务,而采用了一个父类模板就将所有的业务都省略了,其他任何想乣进行用户验证。异常捕获和业务这些操作的逻辑都只需要继承BusinessTemplate,然后写用户的逻辑代码就可以了,再也不用写那些重复的逻辑了,spring正是采用了这样的方法来封装了数据库操作的Connection,Statement这些连接、关闭及异常捕获等。

使用JDBC模板:

  ▲JdbcTemplate:最基本的spring JDBC模板,这个模板支持最简单的JDBC数据库访问功能以及简单的索引参数查询

  ▲NamedParameterJdbcTemplate:使用该模板类执行查询时,可以将查询值以命名参数的形式绑定到SQL中,而不是使用简单的索引参数

  ▲SimpleJdbcTemplate:该模板利用java 5的一些特性,如自动装箱,泛型以及可变参数列表来简化JDBC模板的使用

  2.JdbcTemplate

  spring提高了org.springframework.jdbc.core.JdbcTemplate类,它封装了数据库的操作的方法。JdbcTemplate的构造函数接受一个DataSource对象,使用JdbcTemplate template=new JdbcTemplate(dataSource)来完成JdbcTemplate的初始化,然后就可以使用JdbcTemplate来操作数据库了。将UserDAO使用JdbcTemplate为:

package spring.chapter4;

import java.awt.List;
import java.util.Iterator;
import java.util.Map; import javax.activation.DataSource; import org.springframework.jdbc.core.JdbcTemplate; public class UserDAO1 implements IUserDAO {
private JdbcTemplate jdbctemplate;
public void setDataSource(DataSource dataSource) {
jdbctemplate = new JdbcTemplate(dataSource);
}
public void insert(User user) {
String name=user.getUsername();
String password=user.getPassword();
this.jdbctemplate.update("insert into user (username,password)"+"values('"+name+"','"+password+"')");
}
public User find(Long id) {
List list=jdbctemplate.queryForList("select * form user where id="+id.longValue());
Iterator it=list.iterator();
if(it.hasNext()) {
Map map=(Map) it.next();
Long l=new Long(map.get("id").toString());
String name=map.get("username").toString();
String password=map.get("password").toString();
User user=new User();
user.setId(l);
user.setUsername(name);
user.setPassword(password);
return user;
}
return null;
}
//省略其他方法
}

  2.1使用JdbcTemplate查询数据库

    (1)返回单个对象查询:

     Object query(String sql,ResultSetExtractor extractor)

     Object query (String sql,Object[] args,ResultSetExtractor extractor)

     int queryForInt(String sql)

     int queryForInt(String sql,Object[] args)

     int queryForLong(String sql)

     long queryForLong(String sql,Object[] args)

     Object queryForObject(String sql,Class requiredType)

     Object queryForObject(String sql,Object[] args,Class requiredType)

     Object queryForObject(String sql,RowMapper rowMapper)

     Object queryForObject(String sql,Object[] args,RowMapper rowMapper)

    (2)返回多个对象查询:

     List query(String sql,RowMapper rowMapper)

     List query(String sql,Object[] args,RowMapper rowMapper)

     List queryForList(String sql)

     List queryForList(String sql,Object[] args)

     List queryForList(String,Class elementType)

  2.2使用JdbcTemplate更新数据

    void execute(String sql)

    Object execute(String sql,PrepareStatementCallback action)

    Object execute(ConnectionCallback action)

    int update(String sql)

    int update(String sql,Object[] args)

    int update(PrepareStatementCreator psc)

    int update(String sql,PreparestatementSetter pss)

    int update(String sql,Object[] args,int[] argTypes)

  2.3面向对象查询数据

  spring JDBC的操作还是使用了sql语句,如果对sql不是非常熟悉的程序员可能在运用上有麻烦,为此spring提供了org.springframework.jdbc.object包来设计完全面向对象查询,只要封装一个面向对象的查询类,丝毫不用写任何sql语句就可以完成JdbcTemplate所有的数据库操作功能。

    (1)org.springframework.jdbc.object.SqlQuery

    (2)org.springframework.jdbc.object.MappingSqlQuery

    (3)org.springframework.jdbc.object.SqlUpdate

    (4)org.springframework.jdbc.object.SqlFunction

    

  3.NameParameterJdbcTemplate:

  4.SimpleJdbcTemplate:

spring学习(四)spring 持久层的封装的更多相关文章

  1. Spring学习(四)-----Spring Bean引用同xml和不同xml bean的例子

    在Spring,bean可以“访问”对方通过bean配置文件指定相同或不同的引用. 1. Bean在不同的XML文件 如果是在不同XML文件中的bean,可以用一个“ref”标签,“bean”属性引用 ...

  2. Spring Boot 入门之持久层篇(三)

    原文地址:Spring Boot 入门之持久层篇(三) 博客地址:http://www.extlight.com 一.前言 上一篇<Spring Boot 入门之 Web 篇(二)>介绍了 ...

  3. (转)SpringMVC学习(四)——Spring、MyBatis和SpringMVC的整合

    http://blog.csdn.net/yerenyuan_pku/article/details/72231763 之前我整合了Spring和MyBatis这两个框架,不会的可以看我的文章MyBa ...

  4. Spring Boot 项目学习 (四) Spring Boot整合Swagger2自动生成API文档

    0 引言 在做服务端开发的时候,难免会涉及到API 接口文档的编写,可以经历过手写API 文档的过程,就会发现,一个自动生成API文档可以提高多少的效率. 以下列举几个手写API 文档的痛点: 文档需 ...

  5. Spring学习(十一)-----Spring使用@Required注解依赖检查

    Spring学习(九)-----Spring依赖检查 bean 配置文件用于确定的特定类型(基本,集合或对象)的所有属性被设置.在大多数情况下,你只需要确保特定属性已经设置但不是所有属性.. 对于这种 ...

  6. Spring学习(六)-----Spring使用@Autowired注解自动装配

    Spring使用@Autowired注解自动装配 在上一篇 Spring学习(三)-----Spring自动装配Beans示例中,它会匹配当前Spring容器任何bean的属性自动装配.在大多数情况下 ...

  7. spring boot整合双持久层框架jpa、mybatis

    公司之前用的是spring boot + jpa,但由于jpa无法完美的解决某些动态查询问题,就使用的jdbcTemplate 动态封装SQL,由于代码相对复杂,可读性差,现准备再引入mybatis. ...

  8. Spring学习四----------Bean的配置之Bean的配置项及作用域

    © 版权声明:本文为博主原创文章,转载请注明出处 Bean的作用域(每个作用域都是在同一个Bean容器中) 1.singleton:单例,指一个Bean容器中只存在一份(默认) 2.prototype ...

  9. Spring/SpringMVC/MyBatis(持久层、业务层、控制层思路小结)

    准备工作: ## 7 导入省市区数据到数据库中 1. 从FTP下载SQL脚本文件 2. 把脚本文件移动到易于描述绝对路径的位置 3. 进入MySQL控制台 4. 使用`xxx_xxx`数据库 5. 运 ...

随机推荐

  1. php 缓冲函数

    php.ini中有两个关键参数会影响到php的缓存输出控制: output_buffering :on/off 或者整数 .设置为 on 时,将在所有脚本中使用输出缓存控制,不限制缓存的大小.而设置为 ...

  2. 关于cin 与 cout 的加速

    在用cin 与 cout 的时候 可以使用 ios::sync_with_stdio(); cin.tie(); cout.tie(); 这样在输入大数据的时候可以加快许多

  3. phpstorm 2017 关掉变量提示 parameter name hints

    配置面板中搜索 hints 路径 Editor > General > Appearance > Show parameter name hits 去掉前面的勾就行了

  4. MongoDB 配置服务

    参考网址:https://jingyan.baidu.com/article/d5c4b52b906bafda560dc591.html 1.MongoDB 有一个不方便,需要配置服务,默认启动,否则 ...

  5. Quartz.NET 作业调度使用

    Quartz.NET的使用方法有很多,今天使用Quartz.NET3.0.6的时候发现和2.0版本的语法不太一样,百度上找了一圈也没有找到解决办法 后来在GitHub上下载源代码解决了 实现每隔10s ...

  6. GreenPlum 大数据平台--并行备份(四)

    01,并行备份(gp_dump) 1) GP同时备份Master和所有活动的Segment实例 2) 备份消耗的时间与系统中实例的数量没有关系 3) 在Master主机上备份所有DDL文件和GP相关的 ...

  7. 引导篇之web结构组件

    web结构组件有如下几种: 代理 HTTP代理服务器,是Web安全.应用集成以及性能优化的重要组成模块.代理位于客户端和服务器之间,接收所有客户端的HTTP请求,并将这些请求转发给服务器(可能会对请求 ...

  8. mac下安装ionic

    我的mac系统是EI Capitan,如下图所示. ionic是一个跨平台的框架,能够提供高效hybrid app的开发,而且性能接近于原生态,具体请参考:http://ionicframework. ...

  9. c#字典排序

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  10. ElasticSearch:集群(Cluster),节点(Node),分片(Shard),Indices(索引),replicas(备份)之间关系

    [Cluster]集群,一个ES集群由一个或多个节点(Node)组成,每个集群都有一个cluster name作为标识----------------------------------------- ...