Spring 事务配置管理,简单易懂,详细 [声明式]
Spring 事务配置说明
Spring 如果没有特殊说明,一般指是跟数据存储有关的数据操作事务操作;对于数据持久操作的事务配置,一般有三个对象,数据源,事务管理器,以及事务代理机制;
Spring 提供了多种的底层数据源实现,以及多种类型的事务管理器;所有的管理器都基于 PlatformTransactionManager 接口实现各自的事务策略;
Spring 事务管理采用 AOP 切面代理技术实现,AOP 用于分隔关注点,保证事务的原子性,采用一定的技术 把该关注点 (weaving) 织入到 待完善的关注点上,实现单独组件无法实现的功能,以解决面向对象编程在某些方式下难于实现的操作,更好的支持面向对象的开关原则(扩展开放,修改关闭)。
底层数据源配置
首选加载 数据源配置 .properties 文件;
<bean id="loadProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:META-INF/mybatis/mysql.properties</value>
<value>classpath:META-INF/spring/hibernate.properties</value>
</list>
</property>
</bean>
mysql.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/springdb
username=root
password=xxxxx
filters=stat
initialSize=2
maxActive=300
maxWait=60000
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 1
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
poolPreparedStatements=false
maxPoolPreparedStatementPerConnectionSize=200
hibernate.properties:
# hibernate.X
hibernate.connection.driverClass=org.gjt.mm.mysql.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.connection.username=root
hibernate.connection.password=xxxxx
hibernate.show_sql=true
hibernate.hbm2ddl.auto=create-drop
1. JDBC 方式:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
2. c3p0 方式:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 指定连接数据库的驱动 -->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<!-- 指定连接数据库的URL -->
<property name="jdbcUrl" value="jdbc:mysql://localhost/springdb"/>
<!-- 指定连接数据库的用户名 -->
<property name="user" value="root"/>
<!-- 指定连接数据库的密码 -->
<property name="password" value="xxxxx"/>
<!-- 指定连接数据库连接池的最大连接数 -->
<property name="maxPoolSize" value="40"/>
<!-- 指定连接数据库连接池的最小连接数 -->
<property name="minPoolSize" value="1"/>
<!-- 指定连接数据库连接池的初始化连接数 -->
<property name="initialPoolSize" value="1"/>
<!-- 指定连接数据库连接池的连接的最大空闲时间 -->
<property name="maxIdleTime" value="20"/>
</bean>
3. dbcp 方式:
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
4. Alibaba Druid 方式:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" init-method="init" >
<property name="url" value="${url}?useUnicode=true&characterEncoding=utf-8"></property>
<property name="driverClassName" value="${driver}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
<property name="filters" value="${filters}"></property>
<property name="maxActive" value="${maxActive}"></property>
<property name="maxWait" value="${maxWait}"></property>
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}"></property>
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}"></property>
<property name="validationQuery" value="${validationQuery}"></property>
<property name="testWhileIdle" value="${testWhileIdle}"></property>
<property name="testOnBorrow" value="${testOnBorrow}"></property>
<property name="testOnReturn" value="${testOnReturn}"></property>
<property name="poolPreparedStatements" value="${poolPreparedStatements}"></property>
<property name="maxPoolPreparedStatementPerConnectionSize" value="${maxPoolPreparedStatementPerConnectionSize}"></property>
</bean>
5. JNDI 全局配置方式:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${jndiName}"></property>
</bean>
6. 自定义 DataSource:
<bean id="dataSource" class="me.study.hnmapper.utils.CustomDataSource">
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="driverUrl" value="jdbc:oracle:thin:@10.30.2.204:1527:sec"></property>
<property name="username" value="apps"></property>
<property name="password" value="secapp29"></property>
</bean>
CustomDataSource:
package me.study.hnmapper.utils; import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger; import javax.sql.DataSource; public class CustomDataSource implements DataSource { private String driverClass;
private String driverUrl;
private String username;
private String password; @Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub } @Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub } @Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
} @Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
} @Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
} @Override
public Connection getConnection() throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public Connection getConnection(String username, String password)
throws SQLException {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
Connection conn = null;
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} conn = DriverManager.getConnection(driverUrl, username, password); return conn;
} public String getDriverClass() {
return driverClass;
} public void setDriverClass(String driverClass) {
this.driverClass = driverClass;
} public String getDriverUrl() {
return driverUrl;
} public void setDriverUrl(String driverUrl) {
this.driverUrl = driverUrl;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} }
6. Hibernate方式,利用的是SessionFactory作为数据源操作;
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingLocations" >
<list>
<value>classpath*:model/*.hbm.xml</value>
</list>
</property>
<!-- packagesToScan可以自动搜索某个package的全部标记@Entity class -->
<!--
<property name="packagesToScan">
<list>
<value>hibernatelibs.model*</value>
</list>
</property>
-->
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
TransactionManager 事务管理器配置
1. JDBC TransactionManager 配置;
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 配置DataSourceTransactionManager时需要依注入DataSource的引用 -->
<property name="dataSource" ref="dataSource"/>
</bean>
2. hibernate TransactionManager 配置:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
3. Jta TransactionManager 配置:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
Jta 在应用服务器依赖于 JNDI 查找,也可基于 (ObjectWeb)JOTM 或 Atomikos 这样的 userTransaction 来实现。
PlatformTransactionManager 是 Spring 事务策略核心的接口,Spring 并不支持事务的实现,而是负责包装底层的事务,负责分离各种基于PlatformTransaction接口的具体实现。
应用底层支持什么样的事务策略,Spring 就支持什么样的事务策略。
Spring 声明式事务管理是基本 AOP 切面代理技术实现,是基本基于XML 或 Annotation 配置的一种实现,PlatformTransaction 为各种管理机制提供统一操作接口,各种类型的管理机制都得基于 PlatformTransaction 接口实现具体的事务处理,因此,Spring 事务配置可以很容易的在各种类型的事务管理机制间切换。
PlatformTransaction 提供的接口如下:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
比较常用的事务机制还有:(Jdo)JdoTransactionManager,(Jpa)JpaTransactionManager。此外还有:WebSphereUowTransactionManager、WebLogicJtaTransactionManager等类型;
事务代理机制
1. 使用 pointcut 通知方式 (最常见的方式):
首先配置 tx 命名空间:
<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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
配置通知项 <tx:advice
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" /> <!-- 匹配到类下方法的切入点, 比如 query* 表示匹配所有以 query开头的方法 , 这里可以配置事务行为 传播行为propagation, 隔离级别isolation, 超时(秒)timeout_xx, 自读read-only 等 -->
</tx:attributes>
</tx:advice>
<tx:method 配置项:
name: 用于匹配类中的方法,spring 只支持 类下的方法的形式,对于模式匹配,可以支持 perl 的正则表达式,也支持 aspectj ,默认支持 AspectJ;
<tx:method name="*" ... /> <!-- 匹配所有方法 -->
<tx:method name="get*" ... /> <!-- 匹配所有以 get 开头的方法名 -->
<tx:method name="save*" ... /> <!-- 匹配所有以 save 开头的方法名 -->
...
isolation:
1、Serializable:最严格的级别,事务串行执行,资源消耗最大; 2、REPEATABLE_READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。 3、READ_COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。 4、Read_Uncommitted:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。 5、Default 默认。
propagation: Spring 支持七种传播行为,比 EJB 的 CMT 还多一种;
1. Required=>PROPAGATION_REQUIRED: 有逻辑事务就加入执行,没有就创建一个新的;
2. RequiresNew=>PROPAGATION_REQUIRES_NEW: 表示每次都会创建一个新事务,事务间不互相影响;
3. Supports=>PROPAGATION_SUPPORTS: 有逻辑事务就加入,没有就以非事务方式执行;
4. NotSupported=>PROPAGATION_NOT_SUPPORTED: 不支持事务,有事务时,暂停,以非事务方式执行;
5. Mandatory=>PROPAGATION_MANDATORY: 以事务方式执行,没有事务时,抛出异常;
6. Never=>PROPAGATION_NEVER: 不支持事务,有事务时,抛出异常;
7. Nested=>PROPAGATION_NESTED: 有事务时,嵌入事务内执行,没有时创建新的事务;(内部事务异常不影响外部事务,外部事务异常会影响到内部的事务)
timeout="5" 或 timeout_xx: 比如: timeout_5; 表示超时 5 秒;
完整的一个 tx:method:
<tx:method propagation="REQUIRED" isolation="REPEATABLE_READ" timeout="5" read-only="true" />
另外一种配置方式,是配置在具体bean内的:
<bean id="xxxxDao">
<!-- ... -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,REPEATABLE_READ,timeout_5,readOnly</prop>
</props>
</property>
</bean>
配置 aop:config :
<aop:config>
<!-- 表示在所有切入点加注事务管理 -->
<aop:pointcut expression="execution(* springlibs.service.*.*(..))" id="puintCutid" /> <!-- 需要配置 component-scan -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="puintCutid" />
</aop:config>
expression表达式 : execution(* springlibs.service.*.*(..))
第一个 * : 表示所有的返回值类型;
第二个 * : 表示所有的类;
第三个 * : 表示所有的方法;
切入点表达式例子:
1>. execution(* springlibs.service.*.*(..)) 表示 springlibs.service 下所有的类跟所有的方法;
2>. execution(* springlibs.service.*.save*(..)) 表示 springlibs.service 下所有的以 save 开头的方法;
3>. execution(public * springlibs.service.*.*(..)) 表示 springlibs.service 下所有的公共方法;
pointcut 表示的是一些连接点的集合,使用 expression 来表达这种集合;advisor 这里就当做连接 pointcut切入点 与 advice通知 的作用;
2. 一个 bean 对应一个事务;
配置 dao 实现 bean:
<bean id="xxxDaotarget" class="springlibs.dao.xxxDaoImpl">
<!--
property name="sessionFactory" ref="sessionFactory" />
-->
</bean>
在 Dao 上配置事务:
<bean id="xxxDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="xxxDaotarget" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
3. 所有 bean 共享一个基类:
<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
在 Dao 上配置事务:
<bean id="xxxDao" parent="transactionBase">
<property name="target">
<bean id="xxxDaoImpl" class="springlibs.dao.xxxDaoImpl"></bean>
</property>
</bean>
4. 使用拦截器:
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
在 Dao 上配置事务;
<!-- 配置DAO实现 -->
<bean id="xxxDao" class="springlibs.dao.xxxDaoImpl">
<!--
<property name="sessionFactory" ref="sessionFactory" />
-->
</bean>
5. 使用 Annotation 方式:
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
proxy-target-class 为 true: 使用 CGLib 创建增加的代理;为 false 就是使用 标准 JDK 将会被创建;
可以在 类级别或方法 上使用 @Transaction 注入;
加注 @Transaction 的类或方法,本身并没有事务行为,能被识别为事务的,其实是 tx:annotation-driven 的配置开启了事务;
Spring 事务配置管理,简单易懂,详细 [声明式]的更多相关文章
- 【spring 7】spring和Hibernate的整合:声明式事务
一.声明式事务简介 Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者 ...
- Spring boot 入门五:springboot 开启声明式事务
springboot开启事务很简单,只需要一个注解@Transactional 就可以了.因为在springboot中已经默认对jpa.jdbc.mybatis开启了事务.这里以spring整合myb ...
- spring security 一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中 配置的Bean,充分利用了Spring ...
- 9.spring:事务管理(下):声明式事务管理
声明式事务管理 sprin的声明式事务是管理AOP技术实现的事务管理,其本质是是对方法前后进行拦截,然后 在目标方法开始之前创建或者加入一个事务,在执行完成目标方法之后根据执行情况提交或者回滚事务. ...
- Spring(四)-- JdbcTemplate、声明式事务
1.Spring提供的一个操作数据库的技术JdbcTemplate,是对Jdbc的封装.语法风格非常接近DBUtils. JdbcTemplate可以直接操作数据库,加快效率,而且学这个JdbcT ...
- Spring Boot2 系列教程 (十) | 实现声明式事务
前言 如题,今天介绍 SpringBoot 的 声明式事务. Spring 的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了 API 用于开启事务.提交事务来完成数据操作,或者在发生错误 ...
- Spring Cloud官方文档中文版-声明式Rest客户端:Feign
官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feign 文中例子我做了一些测试在:http ...
- JAVAWEB 一一 框架整合(SSH,Spring+Struts2+Hibernate IOC/DI AOP声明式事务处理 定时任务)
package org.springframework.orm.hibernate3; import java.io.Serializable; import java.util.List; impo ...
- Spring源码窥探之:声明式事务
1. 导入驱动,连接池,jdbc和AOP的依赖 <!-- c3p0数据库连接池 --> <dependency> <groupId>c3p0</groupId ...
随机推荐
- 获取某地的经纬度 && 通过经纬度获取相应的地理位置
最近要通过一个经纬度判断该经纬度是否位于某个地区内,所以通过网上查找资料,整合后出了下面的内容. 1.通过地址获取改地址的经纬度 /** * @param addr * 查询的地址 * @return ...
- Ubuntu 14.04(32位)安装Oracle 11g(32位)全过程
1.将系统更新到最新:sudo apt-get updatesudo apt-get dist-upgrade2.安装Oracle所需的依赖包:sudo apt-get install automak ...
- Programming ActionScript 3.0 for Flash
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7ec ...
- leetcode-Spiral Matrix II 螺旋矩阵2之python大法好,四行就搞定,你敢信?
Spiral Matrix II 螺旋矩阵 Given an integer n, generate a square matrix filled with elements from 1 to n2 ...
- POJ 2891 Strange Way to Express Integers【扩展欧几里德】【模线性方程组】
求解方程组 X%m1=r1 X%m2=r2 .... X%mn=rn 首先看下两个式子的情况 X%m1=r1 X%m2=r2 联立可得 m1*x+m2*y=r2-r1 用ex_gcd求得一个特解x' ...
- POJ 2773 Happy 2006【GCD/欧拉函数】
根据欧几里德算法,gcd(a,b)=gcd(a+b*t,b) 如果a和b互质,则a+b*t和b也互质,即与a互质的数对a取模具有周期性. 所以只要求出小于n且与n互质的元素即可. #include&l ...
- (已解决) 未能加载文件或程序集“Newtonsoft.Json, Version=4.0.0.0, Culture=neutral,
在项目web.config里面添加: <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30AD4F ...
- 实现了一个简单的cage变形器
今天实现了一个简单变形器,可以用一个网格的形状影响另一个网格的形状. 如图,蓝色网格的形状被灰色网格操控. 当前的算法非常简单,就是计算蓝色网格每个点到灰色网格每个点的距离,以距离x次方的倒数作为权重 ...
- Javascript 中的 in, hasOwnProperty, delete, for/in
in 运算符 判断对象是否拥有某一属性只要对象拥有该属性,就会返回true,否则false var point = { x:1, y:1 };alert( 'x' in point ); //tru ...
- 如何在mac上安装gradle
首先,先download最新版本的gradle,网址如下:http://www.gradle.org/get-started然后将下载下来的zip包放在你要安装的路径上,我安装在/usr/local/ ...