Spring 事务配置管理,简单易懂,详细 [声明式]
本文内容纲要:
Spring事务配置说明
Spring如果没有特殊说明,一般指是跟数据存储有关的数据操作事务操作;对于数据持久操作的事务配置,一般有三个对象,数据源,事务管理器,以及事务代理机制;
Spring提供了多种的底层数据源实现,以及多种类型的事务管理器;所有的管理器都基于PlatformTransactionManager接口实现各自的事务策略;
Spring事务管理采用AOP切面代理技术实现,AOP用于分隔关注点,保证事务的原子性,采用一定的技术把该关注点(weaving)织入到待完善的关注点上,实现单独组件无法实现的功能,以解决面向对象编程在某些方式下难于实现的操作,更好的支持面向对象的开关原则(扩展开放,修改关闭)。
底层数据源配置
首选加载数据源配置.properties文件;
<beanid="loadProperties"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<propertyname="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=SELECT1
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
-
JDBC方式:
-
c3p0方式:
-
dbcp方式:
-
AlibabaDruid方式:
-
JNDI全局配置方式:
-
自定义DataSource:
CustomDataSource:
packageme.study.hnmapper.utils;
importjava.io.PrintWriter;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.SQLException;
importjava.sql.SQLFeatureNotSupportedException;
importjava.util.logging.Logger;
importjavax.sql.DataSource;
publicclassCustomDataSourceimplementsDataSource{
privateStringdriverClass;
privateStringdriverUrl;
privateStringusername;
privateStringpassword;
@Override
publicPrintWritergetLogWriter()throwsSQLException{
//TODOAuto-generatedmethodstub
returnnull;
}
@Override
publicvoidsetLogWriter(PrintWriterout)throwsSQLException{
//TODOAuto-generatedmethodstub
}
@Override
publicvoidsetLoginTimeout(intseconds)throwsSQLException{
//TODOAuto-generatedmethodstub
}
@Override
publicintgetLoginTimeout()throwsSQLException{
//TODOAuto-generatedmethodstub
return0;
}
@Override
publicLoggergetParentLogger()throwsSQLFeatureNotSupportedException{
//TODOAuto-generatedmethodstub
returnnull;
}
@Override
public<T>Tunwrap(Class<T>iface)throwsSQLException{
//TODOAuto-generatedmethodstub
returnnull;
}
@Override
publicbooleanisWrapperFor(Class<?>iface)throwsSQLException{
//TODOAuto-generatedmethodstub
returnfalse;
}
@Override
publicConnectiongetConnection()throwsSQLException{
//TODOAuto-generatedmethodstub
returnnull;
}
@Override
publicConnectiongetConnection(Stringusername,Stringpassword)
throwsSQLException{
//TODOAuto-generatedmethodstub
//TODOAuto-generatedmethodstub
Connectionconn=null;
try{
Class.forName(driverClass);
}catch(ClassNotFoundExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
conn=DriverManager.getConnection(driverUrl,username,password);
returnconn;
}
publicStringgetDriverClass(){
returndriverClass;
}
publicvoidsetDriverClass(StringdriverClass){
this.driverClass=driverClass;
}
publicStringgetDriverUrl(){
returndriverUrl;
}
publicvoidsetDriverUrl(StringdriverUrl){
this.driverUrl=driverUrl;
}
publicStringgetPassword(){
returnpassword;
}
publicvoidsetPassword(Stringpassword){
this.password=password;
}
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
this.username=username;
}
}
Hibernate方式,利用的是SessionFactory作为数据源操作;
TransactionManager事务管理器配置
-
JDBCTransactionManager配置;
-
hibernateTransactionManager配置:
-
JtaTransactionManager配置:
Jta在应用服务器依赖于JNDI查找,也可基于(ObjectWeb)JOTM或Atomikos这样的userTransaction来实现。
PlatformTransactionManager是Spring事务策略核心的接口,Spring并不支持事务的实现,而是负责包装底层的事务,负责分离各种基于PlatformTransaction接口的具体实现。
应用底层支持什么样的事务策略,Spring就支持什么样的事务策略。
Spring声明式事务管理是基本AOP切面代理技术实现,是基本基于XML或Annotation配置的一种实现,PlatformTransaction为各种管理机制提供统一操作接口,各种类型的管理机制都得基于PlatformTransaction接口实现具体的事务处理,因此,Spring事务配置可以很容易的在各种类型的事务管理机制间切换。
PlatformTransaction提供的接口如下:
publicinterfacePlatformTransactionManager{
TransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException;
voidcommit(TransactionStatusstatus)throwsTransactionException;
voidrollback(TransactionStatusstatus)throwsTransactionException;
}
比较常用的事务机制还有:(Jdo)JdoTransactionManager,(Jpa)**JpaTransactionManager。**此外还有:WebSphereUowTransactionManager、WebLogicJtaTransactionManager等类型;
事务代理机制
1.使用pointcut通知方式(最常见的方式):
首先配置tx命名空间:
<beansxmlns="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/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
配置通知项<tx:advice
<tx:adviceid="txAdvice"transaction-manager="transactionManager">
<tx:attributes>
<tx:methodname="*"/><!--匹配到类下方法的切入点,比如query*表示匹配所有以query开头的方法,这里可以配置事务行为 传播行为propagation,隔离级别isolation,超时(秒)timeout_xx,自读read-only等-->
</tx:attributes>
</tx:advice>
<tx:method配置项:
name:用于匹配类中的方法,spring只支持类下的方法的形式,对于模式匹配,可以支持perl的正则表达式,也支持aspectj,默认支持AspectJ;
<tx:methodname="*".../><!--匹配所有方法-->
<tx:methodname="get*".../><!--匹配所有以get开头的方法名-->
<tx:methodname="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:methodpropagation="REQUIRED"isolation="REPEATABLE_READ"timeout="5"read-only="true"/>
另外一种配置方式,是配置在具体bean内的:
<beanid="xxxxDao">
<!--...-->
<propertyname="transactionAttributes">
<props>
<propkey="*">PROPAGATION_REQUIRED,REPEATABLE_READ,timeout_5,readOnly</prop>
</props>
</property>
</bean>
配置aop:config:
<aop:config>
<!--表示在所有切入点加注事务管理-->
<aop:pointcutexpression="execution(*springlibs.service.*.*(..))"id="puintCutid"/><!--需要配置component-scan-->
<aop:advisoradvice-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:
<beanid="xxxDaotarget"class="springlibs.dao.xxxDaoImpl">
<!--
propertyname="sessionFactory"ref="sessionFactory"/>
-->
</bean>
在Dao上配置事务:
<beanid="xxxDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--配置事务管理器-->
<propertyname="transactionManager"ref="transactionManager"/>
<propertyname="target"ref="xxxDaotarget"/>
<!--配置事务属性-->
<propertyname="transactionAttributes">
<props>
<propkey="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
3.所有bean共享一个基类:
<beanid="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true"abstract="true">
<!--配置事务管理器-->
<propertyname="transactionManager"ref="transactionManager"/>
<!--配置事务属性-->
<propertyname="transactionAttributes">
<props>
<propkey="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
在Dao上配置事务:
<beanid="xxxDao"parent="transactionBase">
<propertyname="target">
<beanid="xxxDaoImpl"class="springlibs.dao.xxxDaoImpl"></bean>
</property>
</bean>
4.使用拦截器:
<beanid="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<propertyname="transactionManager"ref="transactionManager"/>
<!--配置事务属性-->
<propertyname="transactionAttributes">
<props>
<propkey="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<beanclass="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<propertyname="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
<propertyname="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
在Dao上配置事务;
<!--配置DAO实现-->
<beanid="xxxDao"class="springlibs.dao.xxxDaoImpl">
<!--
<propertyname="sessionFactory"ref="sessionFactory"/>
-->
</bean>
5.使用Annotation方式:
<tx:annotation-driventransaction-manager="transactionManager"proxy-target-class="true"/>
proxy-target-class为true:使用CGLib创建增加的代理;为false就是使用标准JDK将会被创建;
可以在类级别或方法上使用@Transaction注入;
加注@Transaction的类或方法,本身并没有事务行为,能被识别为事务的,其实是tx:annotation-driven的配置开启了事务;
本文内容总结:
原文链接:https://www.cnblogs.com/editor/p/4054498.html