不明觉厉的spring(4)---spring对持久层(jdbc,hibernate)以及事务的支持
2013-10-15 23:45
369 查看
Spring对持久层的支持
1.简述
① JDBC,② O/R Mapping(Hibernate,TopLink等)Spring对持久层支持采用的策略:
1、Spring对持久层“不发明重复的轮子”,即没有重新实现新的持久层方案,对现有持久层方案做封装,更利于使用。
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>
方式四: 直接使用容器提供的数据源(如Tomcat,Weblogic,Sun 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 ,如MysqlRead Uncommited:读未提交数据(会出现脏读,不可重复读和幻读)。
Read Commited:读已提交数据(会出现不可重复读和幻读)
Repeatable Read:可重复读(会出现幻读)
Serializable:串行化
脏读:一个事务读取到另一事务未提交的更新新据。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。
幻读:一个事务读取到另一事务已提交的insert数据。
Spring事务与EJB事务
1、EJB事务:EJB的CMT管理事务方式,只能设置事务边界(传播行为),对于隔离性是不能设置的,并且EJB不支持嵌套事务。
2、Spring事务:
对于Spring来说, Spring的声明式事务可以设置事务边界(传播行为),设置隔离级别,设置只读事务,回滚规则(+:对于任何异常都提交,-:对于任何异常都回滚)
<property name=”transactionAttributes”>
<props>
<prop key=”*”>+异常类型1,-异常类型2</prop>
</property>
PS:Spring对嵌套事务的支持依赖与数据库底层对嵌套式事务的支持。
相关文章推荐
- Spring笔记整理——持久层的支持(jdbc,hibernate)
- Atomikos+Spring+Hibernate支持多数据源+事务回滚
- Spring - Spring对JDBC和Hibernate的支持
- [Spring学习笔记 7 ] Spring中的数据库支持 RowMapper,JdbcDaoSupport 和 事务处理Transaction
- Spring JDBC-Spring对事务管理的支持
- spring----AOP注解以及spring的JDBC和事务
- Spring混合框架(Hibernate+JDBC/iBatis)的事务管理
- Spring整合hibernate的事务属性介绍以及声明式事务管理 (使用Annotation和xml)
- Spring 对 JDBC 的支持与Spring 中的事务管理
- 什么是Spring的DAO,Spring对JDBC/Hibernate的支持
- Jdbc事务以及Spring事务解惑
- Spring整合hibernate的事务属性介绍以及声明式事务管理 (使用Annotation和xml)
- 结合spring+hibernate与jdbc的事务,From 荣浩
- spring04 数据库操作 spring+jdbc/hibernate 及其声明式事务处理
- Spring,Hibernate,Mybatis,JDBC事务之间的的关系
- Spring对JDBC提供支持----对Hibernate集成支持
- springMVC+hibernate+jdbc+mybatis整合 支持全注解方式 支持全配置方式
- Spring中事务管理支持哪几种方式以及每种方式的具体使用方法
- Hibernate延迟加载以及利用Spring事务完美解决延迟加载问题
- day44 spring+jdbc(事务)==>spring+hibernate(事务)