不明觉厉的spring(4)---spring对持久层(jdbc,hibernate)以及事务的支持

Spring对持久层的支持

1.简述

① JDBC,② O/R MappingHibernateTopLink等)

Spring对持久层支持采用的策略:

  1Spring对持久层“不发明重复的轮子”,即没有重新实现新的持久层方案,对现有持久层方案做封装,更利于使用。

  2、采用DAO模式

  3、提供了大量的模板类来简化编程(HibernateDaoSupport,JdbcTemplate等)

  4、重新设计了一套完善的异常体系结构

    ① 类型丰富,细化异常类型

    ② 全都是运行时异常(RuntimeException

2.spring的数据访问模板

模板类                     功能
CciTemplate JacCci连接,适用于WebLogic,WebSphere平台
JdbcTemplate JDBC连接
NameParameterJdbcTemplate 支持参数命名的JDBC连接
SimpleJdbcTemplate JDBC连接
HibernateTemplate 支持Hibernate2,3的会话
JpaTempate Java存储JPA实体管理
SqlMapClientTemplate iBatis

注意:在纯Hibernate项目中,SessionFactory接口获取Session并与数据库进行会话。而Spring的HibernateTemplate在Hibernate Session基础上提供了一个抽象层。
其主要功能是简化打开和关闭Hibernate会话工作,并将Hibernate异常转化为Spring的ORM异常之一。只是抽象了相关框架的操作
使用spring的每个模板需要相应的xml配置比如使用HibernateTemplate需要添加hibernatejar包并在xml配置如下:

<!--  配置sessionFactory --> 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
 <property name="configLocation">
  <value>classpath:hibernate.cfg.xml</value> 
  </property>
  </bean>
<!--配置hibernate的模板-->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
    <property name="sesscionFactory" ref="sessionFactory"></property>
</bean>

使用DAO的支持类:
前面说的是DAO的模板。现在说的是DAO模板的支持类。
数据访问模板,并不是Spring的全部,每个模板还提供了一些有用的方法,让我们不必创建明确的回调实现。
同时,Spring提供了DAO的支持类,用于派生出我们自己的DAO类。
如:如果程序DAO继承了JdbcDaoSupport支持类,那么我们只需要调用getJdbcTemplate访问就可以获取一个JdbcTemplate模板。
Spring提供的支持类如下:
DAO支持类
CciDaoSupport
JdbcDaoSupport
NameParameterJdbcDaoSupport
HibernateDaoSupport
SqlMapClientDaoSupport

spring对jdbc的支持

1、配置数据源

    方式一:采用Spring内置的数据源,Spring内置实现 DriverManagerDataSource

<bean id="dataSource"   class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName">
         <value>com.mysql.jdbc.Driver</value>
         </property>
         <property name="url">
         <value>jdbc:mysql://localhost:3306/senssic</value>
         </property>
         <property name="username">
         <value>root</value>
         </property>
         <property name="password">
         <value>qiyu0126</value>
         </property>
</bean>

方式二:采用开源数据库产品如DBCP

DBCP提供的BasicDataSource

需要下载commons-dbcpjar包和 commons-pool.jar

http://archive.apache.org/dist/commons/dbcp/binaries/commons-dbcp-1.2.1.zip

http://jarfiles.pandaidea.com/c/commons-pool/commons-pool-1.5.jar.zip

 <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/senssic</value>
    </property>
    <property name="username">
      <value>root</value>
    </property>
    <property name="password">
      <value>qiyu0126</value>
    </property>
         <!-- 连接池启动时的初始值 -->
	 <property name="initialSize" value="1"/>
	 <!-- 连接池的最大值 -->
	 <property name="maxActive" value="500"/>
	 <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
	 <property name="maxIdle" value="2"/>
	 <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
	 <property name="minIdle" value="1"/>
    </bean>
也可以写一个propertis文件来配置数据源然后用占位的方式映射到xml中

<context:property-placeholder location=“jdbc.properties”/> <!--指定properties文件,classees路径下-->
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName" value="${driverClassName}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
     <!-- 连接池启动时的初始值 -->
	 <property name="initialSize" value="${initialSize}"/>
	 <property name="maxActive" value="${maxActive}"/>
	 <property name="maxIdle" value="${maxIdle}"/>
	 <property name="minIdle" value="${minIdle}"/>
  </bean>

方式三:采用开源数据库产品c3po连接池
需要下载c3pO-0.9.1.2jar包 

   <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy- 
method="close" lazy-init="false"> 
        <property name="driverClass" value="com.mysql.jdbc.Driver"/> 
        <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/senssic"/> 
        <property name="user" value="root" /> 
        <property name="password" value="qiyu0126" /> 
        <property name="testConnectionOnCheckin" value="true" /> 
        <property name="automaticTestTable" value="TestTable" /> 
        <property name="idleConnectionTestPeriod" value="18" /> 
        <property name="maxIdleTime" value="250" /> 
        <property name="testConnectionOnCheckout" value="true" /> 
    </bean>


 方式四: 直接使用容器提供的数据源(如TomcatWeblogicSun Application Server

    JNDI数据源:(mysql5,tomcat5.5)

    step1:

       在server.xml中:

       <Resource name="jdbc/mydatasource" auth="Container" description="DB Connection" 

    type="javax.sql.DataSource" username="root" password="qiyu0126" 

    driverClassName="com.mysql.jdbc.Driver" 

    url="jdbc:mysql://localhost:3306/senssic" maxActive="5" />

    step2:

    在context.xml中(conf\context.xml):

    <ResourceLink   name="jdbc/mydatasource"        global="jdbc/mydatasource"   type="javax.sql.DataSourcer"/> 

    step3:

    在beans-config.xml:

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

        <property name="jndiName">

          <value>java:jdbc/mydatasource</value>

        </property>

      </bean>

1、使用Spring的jdbcTemplate进一步简化JDBC操作

在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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.1.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config></context:annotation-config>


 <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/senssic</value>
    </property>
    <property name="username">
      <value>root</value>
    </property>
    <property name="password">
      <value>qiyu0126</value>
    </property>
         <!-- 连接池启动时的初始值 -->
	 <property name="initialSize" value="1"/>
	 <!-- 连接池的最大值 -->
	 <property name="maxActive" value="500"/>
	 <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
	 <property name="maxIdle" value="2"/>
	 <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
	 <property name="minIdle" value="1"/>
    </bean>
    
<!-- 配置spring的jdbcTemplate -->
<bean id="jdbcTemplate"
        class="org.springframework.jdbc.core.JdbcTemplate" abstract="false"
        lazy-init="false" autowire="default" >
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
    </bean>
   <!-- 配置spring的事务管理 (DataSourceTransactionManager提供对JDBC,iBatis的支持,DataSource,当然还有JtaTransactionManager 对应JTA事务,还有hibernate的一套事务管理)-->
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  	<property name="dataSource" ref="dataSource"/>
  </bean>
  <!-- 自己定义的dao -->
  <bean id="mydao" class="spring.senssic.tx.MyDao">
  </bean>
</beans>

dao的业务代码:

package spring.senssic.tx;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class MyDao {
	@Resource(name = "jdbcTemplate")//使用注解的方式由spring自动注入
	private JdbcTemplate jt;

	public List<Person> findALL() {
		@SuppressWarnings("unchecked")
		RowMapper<Person> rowMapper = new RowMapper() {
			@Override
			public Object mapRow(ResultSet rs, int arg1) throws SQLException {
				Person person = new Person();
				person.setAge(rs.getInt("age"));
				person.setName(rs.getString("name"));
				return person;
			}
		};
		return jt.query("select * from sen", rowMapper);

	}

}

bean类:
package spring.senssic.tx;

public class Person {
	private int age;
	private String name;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
junit测试类:

package spring.senssic.test;

import java.util.List;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import spring.senssic.temp.AopTo;
import spring.senssic.temp.B;
import spring.senssic.temp.C;
import spring.senssic.temp.D;
import spring.senssic.tx.MyDao;
import spring.senssic.tx.Person;

public class STest {

	@BeforeClass
	public static void TWork() {
		ApplicationContext act = new ClassPathXmlApplicationContext("beans.xml");

		Object d = act.getBean("dataSource");
		System.out.println(d.getClass().getName());
		MyDao mDao = (MyDao) act.getBean("mydao");
		List<Person> list = mDao.findALL();
		for (Person p : list) {
			System.out.println("name:" + p.getName() + "--->age:" + p.getAge());

		}
	}

}


spring对hibernate的支持

Step1:  配置数据源

<bean id="dataSource"   class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName">
         <value>com.mysql.jdbc.Driver</value>
         </property>
         <property name="url">
         <value>jdbc:mysql://localhost:3306/senssic</value>
         </property>
         <property name="username">
         <value>root</value>
         </property>
         <property name="password">
         <value>qiyu0126</value>
         </property>
</bean>
以上三种的任意一种即可

Step2:  配置sessionfactory

   

 <bean id="mySessionFactory"
      class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      <property name="dataSource">
      <ref bean="dataSource" />
      </property>
      <property name="mappingResources">
      <list>
        <value>spring/senssic.hbm.xml</value>
      </list>
      </property>
      <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">
        org.hibernate.dialect.MySQLDialect
        </prop>
        <prop key="hibernate.show_sql">true</prop>
      </props>
      </property>
    </bean>

  Step3:  配置DAO

    <bean id="orderDao" class="spring.Senssic.DAOHibernateImpl">
    <property name="sessionFactory">
      <ref bean="mySessionFactory" />
    </property>
    </bean>

    注意:以上配置是要求dao 继承HibernateDaoSupport

spring对事务的支持

一、AOP事务的含义:

  事务当作一个切面,动态地织入到目标对象,形成一个代理对象。

二、Spring的事务机制

Spring支持声明式事务。

Spring使用事务服务代理和事务管理器(如HibernateTransactionManager)来支持事务服务。

  Spring对事务的边界多了一种嵌套事务(PROPAGATION_NESTED)。

PROPAGATION_NESTED

如果客户端启动了事务T1,那么Bean启动一个嵌套在T1中的子事务T2

如果客户端没有启动事务,那么Bean会启动一个新的事务,类似于REQUIRED_NEW


事务传播属性

REQUIRED:业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务。
NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。
REQUIRESNEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行。
MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。
SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效

Spring中使用Hibernate事务

使用注解配置:
需要在spring的xml配置文件中配置:

<!--  配置sessionFactory --> 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
 <property name="configLocation">
  <value>classpath:hibernate.cfg.xml</value> <!--hibernate的配置文件,里面配置了数据源,可以同刚才上面的sessionfactory创建作比较,上面那个指定数据源-->
  </property>
  </bean>
<!--使用hibernate的事务管理(HibernateTransactionManager对Hibernate的支持,SessionFactory)-->
    <bean id="myTransactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory">
           <ref bean="mySessionFactory" />
         </property>
    </bean>  
 <!– 采用@Transactional注解方式使用事务  ,且被此注解定义的bean受spring管理-->  <tx:annotation-driven transaction-manager="txManager"/>



事物注解方式: @Transactional

最常用:@Transactional(value = "txManager", isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
value:bean中配置的事务处理类   isolation :事务隔离级别     propagation:事物传播行为   rollbackFor:一旦抛异常回滚
timeout:事务超时时间    readOnly:是否为只读事务(只有传播事务为新建才起作用,另外数据库可以对只读优化)

当标于类前时, 标示类中所有方法都进行事物处理
例子:
@Transactional
public class TestServiceBean implements TestService {}
当类中某些方法不需要事物时:
@Transactional
public class TestServiceBean implements TestService {
    
    private TestDao dao;
    
    public void setDao(TestDao dao) {
        this.dao = dao;
    }
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<Object> getAll() {
        return null;
    }
    
}


事物传播行为介绍: 
@Transactional(propagation=Propagation.REQUIRED) 
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) 
容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW) 
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY) 
必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER) 
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS) 
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
事物超时设置:
@Transactional(timeout=30) //默认是30秒
事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化
MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED



xml配置:
<!--  配置sessionFactory 
  --> 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
 <property name="configLocation">
  <value>classpath:hibernate.cfg.xml</value> 
  </property>
  </bean>
 <!--  配置事务管理器 
  --> 
 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
  <ref bean="sessionFactory" /> 
  </property>
  </bean>
 <!--  配置事务的传播特性 
  --> 
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
 <tx:attributes>
  <tx:method name="add*" propagation="REQUIRED" /> 
  <tx:method name="del*" propagation="REQUIRED" /> 
  <tx:method name="modify*" propagation="REQUIRED" /> 
  <tx:method name="*" read-only="true" /> 
  </tx:attributes>
  </tx:advice>
 <!--  那些类的哪些方法参与事务 
  --> 
 <aop:config>
  <aop:pointcut id="allManagerMethod" expression="execution(* spring.senssic.manager.*.*(..))" /> 
  <aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice" /> 
 </aop:config>



数据库系统提供了四种事务隔离级

数据库系统提供了四种事务隔离级别供用户选择。不同的隔离级别采用不同的锁类型来实现,在四种隔离级别中,Serializable的隔离级别最高,Read Uncommited的隔离级别最低。大多数据库默认的隔离级别为Read Commited,如SqlServer,当然也有少部分数据库默认的隔离级别为Repeatable Read ,如Mysql
Read Uncommited:读未提交数据(会出现脏读,不可重复读和幻读)。
Read Commited:读已提交数据(会出现不可重复读和幻读)
Repeatable Read:可重复读(会出现幻读)
Serializable:串行化


脏读:一个事务读取到另一事务未提交的更新新据。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。
幻读:一个事务读取到另一事务已提交的insert数据。

Spring事务与EJB事务

  1EJB事务:

EJBCMT管理事务方式,只能设置事务边界(传播行为),对于隔离性是不能设置的,并且EJB不支持嵌套事务。

2Spring事务:

对于Spring来说, Spring的声明式事务可以设置事务边界(传播行为),设置隔离级别,设置只读事务,回滚规则(+:对于任何异常都提交,-:对于任何异常都回滚)

<property name=”transactionAttributes”>

  <props>

    <prop key=”*”>+异常类型1-异常类型2</prop>

</property>

PSSpring对嵌套事务的支持依赖与数据库底层对嵌套式事务的支持。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值