Spring总结(5):Spring持久化

一、DAO模式

DAO(Data Access Object 数据访问对象)

DAO的主要目的就是将与持久性相关的问题与一般的业务规则和工作隔离开来,它为定义业务层可以访问的持久性操作引入了一个接口并隐藏了实现的具体细节,该接口的功能将依赖于采用的持久性技术而改变,但是DAO接口可以基本保持不变。

DAO是ORM技术的一种实现,采用DAO也能节省程序开发时间,减少代码量和开发成本。


二、Spring DAO理念

1、Spring提供了一套抽象的DAO类,这有利于统一的方式操作各种DAO技术。如JDO、JDBC等,这些抽象DAO类提供了设置数据源以及相关辅助信息的方法,而其中一些方法同具体的DAO技术相关。目前,Spring DAO抽象类提供了以下几种类:

(1)JdbcDaoSupport:JDBC DAO抽象类,使用时需要为它设置数据源,通过子类能过获得JdbcTemplate来访问数据库。

(2)HibernateDAOSupport:Hibernate DAO抽象类。需要为它配置HibernateSessionFactory。通过其子类能够获得Hibernate实现。

(3)JdoDaoSupport:Spring 为JDO通过的DAO抽象类,需要为它配置PersistenceManagerFactory,通过其子类能够获得JdoTemplate。

2、在使用Spring的DAO框架进行数据库存取时,只需通过数据存取接口来操作即可。下面举个小栗子:

(1)新建一个实体对象User,定义对应对数据表字段的属性,并添加有参数的构造方法

package com.itzcn.bean;

public class User {
	private int id;
	private String name;
	private String pass;
	public User(int id,String name,String pass){
		this.id=id;
		this.name=name;
		this.pass=pass;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPass() {
		return pass;
	}
	public void setPass(String pass) {
		this.pass = pass;
	}
	
}

(2)创建接口UserDao,并定义用来添加用户信息的方法addUser(),其参数为User对象

package com.itzcn.dao;

import java.sql.SQLException;

import com.itzcn.bean.User;

public interface UserDao {
	public int addUser(User user) throws SQLException;	
}

 (3)创建UserDao的实现类UserDaoImpl,在其中首先定义一个用于操作数据库的数据源对象DataSource。在addUser()方法的实现中,通过DataSource创建一个数据连接。这个数据源对象在Spring中提供了javax.sql.DataSource接口的实现,只需在Spring的配置文件中进行相关配置即可。

package com.itzcn.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.itzcn.bean.User;
import com.itzcn.dao.UserDao;

public class UserDaoImpl implements UserDao {
	private DataSource dataSource;

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public int addUser(User user) {
		Connection conn=null;
		PreparedStatement pstmt=null;
		int flag=-1;
		try {
			conn=dataSource.getConnection();
			String sql="insert into Info(id,name,pass) values(?,?,?)";
			pstmt=conn.prepareStatement(sql);
			pstmt.setInt(1,user.getId());
			pstmt.setString(2, user.getName());
			pstmt.setString(3, user.getPass());
			flag=pstmt.executeUpdate();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
		return flag;
	}

}

 (4)编写配置文件,在其中定义一个JavaBean名为dataSource的数据源,他是org.apache.commons.dbcp.BasicDataSource类的实例(或者org.springframework.jdbc.datasource.DiverManagerDataSource的实例)。之后配置UserDaoImpl,并注入它的dataSource属性值。

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName">
			<value>com.mysql.jdbc.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://localhost:3306/student</value>
		</property>
		<property name="username">
			<value>root</value>
		</property>
		<property name="password">
			<value>root</value>
		</property>
		
	</bean>
	<!-- 为UserDaoImpl注入数据源 -->
	<bean id="userDao" class="com.itzcn.dao.impl.UserDaoImpl">
		<property name="dataSource">
			<ref local="dataSource"/>
		</property>
	</bean>

</beans>

(5)编写测试类

package com.itzcn.test;

import java.sql.SQLException;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.itzcn.bean.User;
import com.itzcn.dao.UserDao;

public class TestAddUser {


	public static void main(String[] args) throws SQLException {
		Resource resource=new ClassPathResource("applicationContext.xml");
		BeanFactory factory=new XmlBeanFactory(resource);
		UserDao uDao=(UserDao) factory.getBean("userDao");
		User user=new User(0,"Jarray","999999");
		int flag=uDao.addUser(user);
		if(flag>0){
			System.out.println("添加用户成功!");
		}else{
			System.out.println("添加用户失败");
		}
	}

}

 


三、数据源

不管选择哪种Spring Dao 的支持方式,我们都需要在Spring 容器中配置一个数据源应用的bean,一共有以下三种方式配置数据源的引用 
(1)通过JDBC驱动程序定义的数据源 
(2)通过JNDI查找的数据源 
(3)连接池的数据源

1、使用JNDI数据源

可能大家会对JNDI有点陌生,先来简单的解释一下JNDI吧。 
来来来,先举个栗子: 
如果咱们不用JNDI,在做开发时,可能是下面这样来配置数据源的

    <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <!-- 指定连接数据库的URL -->
        <property name="jdbcUrl" value="jdbv:mysql://localhost:3306......" />
        <!-- 指定连接数据库的用户名 -->
        <property name="user" value="userName" />
        <!-- 指定连接数据库的密码 -->
        <property name="password" value="pswd" />
        <!-- 指定连接池中保留的最大连接数. Default:15 -->
        <property name="maxPoolSize" value="100" />
        <!-- 指定连接池中保留的最小连接数 -->
        <property name="minPoolSize" value="10" />
        ......

这样写有个弊端,就是以上这些参数随时都有可能要被更改,用了JNDI之后的做法:在在J2EE容器中配置JNDI参数,定义一个数据源,也就是JDBC引用参数,给这个数据源设置一个名称;然后,在程序中,通过数据源名称引用数据源从而访问后台数据库。 
所以这些参数是从web容器中获取的,并且允许管理员对其进行热切换,是不是很赞呢。

好了,我们来看看怎么在Spring 容器中配置JNDI获取数据源吧

  <jee:jndi-lookup id="dataSource" jndi-name="/jdbc/name" resource-ref="true"/>

这样就可以查找JNDI中的对象(数据源)并将其装配到Spring容器中了。

2、使用数据源连接池

虽然Spring没有提供数据源连接池的实现,但是我们还有很多其他优先的数据源实现,比如DBCP 还有中阿里巴巴的Druid 
https://github.com/alibaba/druid 
现在以阿里的Druid为例

<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--数据库连接-->
        <property name="url" value="${jdbc.url}"/>
        <!--用户名-->
        <property name="username" value="${jdbc.username}"/>
        <!--密码-->
        <property name="password" value="${jdbc.password}"/>
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${jdbc.initialSize}"/>
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="${jdbc.maxActive}"/>
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${jdbc.maxIdle}"/>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${jdbc.minIdle}"/>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${jdbc.maxWait}"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandoned" value="${jdbc.removeAbandoned}"/>
        <!-- 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/>
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="${jdbc.logAbandoned}"/>
        <property name="validationQuery" value="${jdbc.validationQuery}"/>
        <property name="testOnBorrow" value="${jdbc.testOnBorrow}"/>
        <property name="testOnReturn" value="${jdbc.testOnReturn}"/>
        <property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
    </bean>

3、基于JDBC驱动的数据源

在Spring 中,通过JDBC驱动定义数据源是最简单的方式,Spring 提供了两种数据源对象 
DriverManagerDataSource:在每个连接请求时都会返回一个新建的连接 
SingleConnectionDataSourece:在每个连接请求时都会返回一同一个连接。 
实例:


    <bean id="dataSoure" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver"></property>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

四、事务应用的管理

Spring中的事务是基于AOP实现的,而Spring的AOP是以方法为单位的,所以Spring的事务属性就是对事务应用方法上的策略描述。这些属性分为传播行为、隔离级别、只读和超时属性。

事务的管理通常分为两种方式,即编程式事务和声明式事务。

1、编程式事务

在Spring中主要有两种编程式事务管理的实现方法,分别是使用PlatformTransactionManager接口的事务管理器和TransactionTemplate实现。二者各有优缺点,一般推荐后者,因为符合Spring的模板模式。

2、声明式事务

Spring的声明式事务不涉及创建依赖关系,它通过AOP实现事务管理,在使用声明式事务时不需要编写任何代码即可实现基于容器的事务管理。Spring提供了一些可供选择的辅助类,它们简化了传统的数据库操作流程。在一定程度上节省了工作量,提高了编码效率,因此推荐使用这种方式。

在Spring中常用TransactionProxyFactoryBean完成声明式事务管理。

使用TransactionProxyFactoryBean需要注入所要依赖的事务管理,并设置代理的目标对象、代理对象的生成方式和事务属性。代理对象是在目标对象上生成的包含事务和AOP切面的新对象,它可以赋给目标的引用来替代目标对象以支持事务或AOP提供的切面功能。

示例:

(1)新建实体类User,与第二节的一样,这里不再贴出

(2)编写操作数据库的AddUserDao类,并继承JdbcDaoSupport类。在该类的addUser()方法中执行了两次添加数据的操作。这个方法在配置TransactionProxyFactoryBean时被定义为事务性方法,并指定了事务属性,所以方法中的数据库操作都被当作一个事务处理。

package com.itzcn.dao;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import com.itzcn.bean.User;

public class AddUserDao extends JdbcDaoSupport {
	
	public void  addUser(User user){
		String sql="insert into info(id,name,pass) values('"+user.getId()+"','"+user.getName()+"','"+user.getPass()+"')";
		JdbcTemplate jt=getJdbcTemplate();
		jt.execute(sql);
		jt.execute(sql);
	}
}

(3)在配置文件中定义数据源和事务管理器,该管理器被注入到TransactionProxyFactoryBean中,设置代理对象和事务属性。这里的目标对象定义以内部类方式定义

 

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<!-- 定义TransactionProxy -->
	<bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="target">
			<bean id="addUserDao" class="com.itzcn.dao.AddUserDao">
				<property name="dataSource">
					<ref local="dataSource"/>
				</property>
			</bean>
		</property>
		
		<property name="proxyTargetClass" value="true"></property>
		
		<property name="transactionAttributes">
			<props>
				<prop key="add*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>	
	</bean>
	
	<!-- 配置数据源 -->
	<bean  id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql://localhost:3306/student"></property>
		<property name="username" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	<!-- 定义事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref local="dataSource"/>
		</property>
	</bean>

</beans>

(4)创建测试类

package com.itzcn.test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.itzcn.bean.User;
import com.itzcn.dao.AddUserDao;

public class TestAddUser {
	
	public static void main(String[] args) {
		Resource resource=new ClassPathResource("applicationContext.xml");
		BeanFactory factory=new XmlBeanFactory(resource);
		User user=new User(100,"Tom007","Tom007");
		AddUserDao addUserDao=(AddUserDao) factory.getBean("transactionProxy");
		addUserDao.addUser(user);
	}
}

AddUserDao中第二次执行查询时会导致一个异常抛出:

java.lang.NoClassDefFoundError: org/springframework/dao/QueryTimeoutException


五、应用JdbcTemplate操作数据库

JdbcTemplate类是Spring的核心类之一,可以在org.spring.framework.jdbc.core包中找到。该类的在内部已经处理数据库资源的建立和释放,并可以避免一些常见的错误,如关闭连接抛出异常等,因此使用JdbcTemplate类简化了编程JDBC时所需要的基础代码。

JdbcTemplate类可以直接通过数据源的引用实例化,然后在服务中使用,也可以通过依赖注入的方式在ApplicationContext中产生并作为JavaBean的引用给服务使用。

JdbcTemplate类提供了很多重载的方法用于数据库的查询和更新,提高了程序的灵活性。

示例:

(1)新建JdbcTemplate.xml 文件,在其中配置JdbcTemplate和数据源

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource">
			<ref local="dataSource"/>
		</property>
	</bean>
	
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName">
			<value>com.mysql.jdbc.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://localhost:3306/student</value>
		</property>
		<property name="username">
			<value>root</value>
		</property>
		<property name="password">
			<value>root</value>
		</property>		
	</bean>


</beans>

(2)新建测试类,获取JdbcTemplate对象,并利用其update()方法执行数据库的添加操作

package com.itzcn.test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;

public class TestJdbcTemplate {

	public static void main(String[] args) {
		JdbcTemplate jdbcTemplate=null;
		Resource resource=new ClassPathResource("jdbcTemplate.xml");
		BeanFactory factory=new XmlBeanFactory(resource);
		jdbcTemplate=(JdbcTemplate) factory.getBean("jdbcTemplate");
		String sql="insert into info(id,name,pass) values(0,'administrator','abc123')";
		int flag=jdbcTemplate.update(sql);
		if(flag>0){
			System.out.println("添加成功!");
		}else{
			System.out.println("添加失败!");
		}
		
	}

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值