持久层:所谓“持久层”,也就是在系统逻辑层面上,专著于实现数据持久化的一个相对独立的领域(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. css样式继承经验记录

    与元素(文字颜色.字体等)相关的样式默认会被继承: 与元素在页面上的布局相关的样式默认不会被继承: <body> <p>I like <span>aplles< ...

  2. Python异常基础

    一.常见异常及场景举例 1.AssertionError 断言失败,断言是调试中常用(表示自己并不常用┑( ̄Д  ̄)┍)手段 举例: def foo(s): n = int(s) assert n ! ...

  3. jenkins集成python脚本

    Jenkins配置获取源码并构建 1. Jenkins系统设置--管理插件,搜索安装“GitLab”和“Git” 2. 新建任务,选择自由风格项目 3. 源码管理 git (1)Repository ...

  4. git push的一些坑

    在安装git的时候我们一般会自己设置一个用户名和邮箱,这个一般设置为全局的用户名,如下所示 git config --global user.name "xxx" git conf ...

  5. 可编辑的el-table表格,结合input输入,upload文件上传的表格

    最近整理了一下,table表格的编辑状态,把一般表格里需要输入的类型都放进来了,实现的功能如图     这里面的input输入框没什么好说的,绑定对应的值就可以,要注意的是组件上传的upload,这个 ...

  6. Xtts v4变化&先决条件&已知问题

    V4变化的主要有:     1.这个采购使用简化的命令.源的一个命令(--backup)和目标的一个命令(--restore). 2.此过程只需要在源和目标的$ TMPDIR(res.txt)之间复制 ...

  7. ModelSim使用教程

    参考[百度文库]

  8. Lakeshore

    用来做 html5 特效,Egret游戏引擎 为什么用Egret开发的游戏在某些Android设备上特别卡? { 在 Android 早期版本( 4.4 之前) ,Android WebView 并不 ...

  9. django设置打印数据库日志

    在settings.py中添加: LOGGING = { 'disable_existing_loggers': False, 'version': 1, 'handlers': { 'console ...

  10. vue中watch的使用

    vue中watch的使用 vue中的watch是一个比较重要的概念,通过他我们可以检测data的变化,下面进行详细的介绍. watch定义方式如下: {[key: string]: string | ...