??xml version="1.0" encoding="utf-8" standalone="yes"?>
有点学的味道?br />
可能是因为采用其他被创造者不知道的机Ӟ所以被创造者无法理解和知晓?br />
]]>
<aop:config>
<aop:pointcut id="systemDaoMethods" expression="execution(* com.unitedbiz.system.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="systemDaoMethods"/>
</aop:config>
x一下就可以?br />
]]>
{过些时候重新审视自q设计再说
]]>
DataBinder: applyPropertyValues(MutablePropertyValues mpvs)
org.springframework.beans.BeanWrapperImpl: wrapping object [com.unitedbiz.model.User@996f0e]
AbstractPropertyAccessor::setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
org.springframework.beans.BeanWrapperImpl: wrapping object [com.unitedbiz.model.User@996f0e]::setPropertyValue(PropertyValue pv)
一般位|顺序ؓ
encoding
hibernate
localeFilter
securityFilter
sitemesh
getTimeout()ҎQ它q回事务必须在多秒内完成?
isReadOnly(),事务是否只读Q事务管理器能够Ҏq个q回D行优化,保事务是只ȝ?
getIsolationLevel()Ҏq回事务的隔ȝ别,事务理器根据它来控制另外一个事务可以看到本事务内的哪些数据?/p>
在TransactionDefinition接口中定义了五个不同的事务隔ȝ?
ISOLATION_DEFAULT q是一个PlatfromTransactionManager默认的隔ȝ别,使用数据库默认的事务隔离U别.另外四个与JDBC的隔ȝ别相对应
ISOLATION_READ_UNCOMMITTED q是事务最低的隔离U别Q它充许别外一个事务可以看到这个事务未提交的数据。这U隔ȝ别会产生脏读Q不可重复读和像读?
例如:
Mary的原工资?000,财务人员Mary的工资改Z8000Q但未提交事?
Mary发现自己的工资变Z8000Q欢天喜圎ͼ
而胦务发现操作有误,而回滚了事务,Mary的工资又变ؓ?000
ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这U事务隔ȝ别可以避免脏d玎ͼ但是可能会出C可重复读和像读?/p>
ISOLATION_REPEATABLE_READ q种事务隔离U别可以防止脏读Q不可重复读。但是可能出现像读。它除了保证一个事务不能读取另一个事务未提交的数据外Q还保证了避免下面的情况产生(不可重复??/p>
在事?中,Mary d了自q工资?000,操作q没有完?
在事?中,q时财务人员修改了Mary的工资ؓ2000,q提交了事务.
在事?中,Mary 再次d自己的工资时Q工资变Z2000
在一个事务中前后两次d的结果ƈ不致Q导致了不可重复诅R?
使用ISOLATION_REPEATABLE_READ可以避免q种情况发生?/p>
ISOLATION_SERIALIZABLE q是p最高代价但是最可靠的事务隔ȝ别。事务被处理为顺序执行。除了防止脏读,不可重复dQ还避免了像读?/p>
目前工资?000的员工有10人?
事务1,d所有工资ؓ1000的员工?
q时另一个事务向employee表插入了一条员工记录,工资也ؓ1000
事务1再次d所有工资ؓ1000的员?
p取到?1条记录,q就产生了像读?
ISOLATION_SERIALIZABLE能避免这L情况发生。但是这样也耗费了最大的资源?/p>
getPropagationBehavior()q回事务的传播行为,由是否有一个活动的事务来决定一个事务调用?/p>
在TransactionDefinition接口中定义了七个事务传播行ؓ?/p>
PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务?/p>
单独调用methodBҎ
单独调用MethodAӞ在MethodA内又会调用MethodB.
执行效果相当?
PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务理器,PROPAGATION_SUPPORTS与不使用事务有少怸同?/p>
PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务Q则抛出异常?/p>
当调用methodAӞmethodB则加入到methodA的事务中Q事务地执行?/p>
PROPAGATION_REQUIRES_NEW L开启一个新的事务。如果一个事务已l存在,则将q个存在的事务挂赗?/p>
当调用methodA?
PROPAGATION_NOT_SUPPORTED L非事务地执行Qƈ挂vM存在的事务?/p>
PROPAGATION_NEVER L非事务地执行Q如果存在一个活动事务,则抛出异?/p>
PROPAGATION_NESTED如果一个活动的事务存在Q则q行在一个嵌套的事务? 如果没有zd事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执?/p>
q是一个嵌套事?使用JDBC 3.0驱动?仅仅支持DataSourceTransactionManager作ؓ事务理器。需要JDBC 驱动的java.sql.SavepointcR有一些JTA的事务管理器实现可能也提供了同样的功能?/p>
使用PROPAGATION_NESTEDQ还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true;
而nestedTransactionAllowed属性值默认ؓfalse;
如果调用methodAҎQ相当于下面的效?
嵌套事务一个非帔R要的概念是内层事务依赖于外层事务。外层事务失败时Q会回滚内层事务所做的动作。而内层事务操作失败ƈ不会引v外层事务的回?/strong>?/p>
PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区?/strong>:它们非常cM,都像一个嵌套事务,如果不存在一个活动的事务Q都会开启一个新的事务。用PROPAGATION_REQUIRES_NEWӞ内层事务与外层事务就像两个独立的事务一P一旦内层事务进行了提交后,外层事务不能对其q行回滚。两个事务互不媄响。两个事务不是一个真正的嵌套事务。同时它需要JTA事务理器的支持? PROPAGATION_REQUIRED应该是我们首先的事务传播行ؓ。它能够满我们大多数的事务需求?/p>
使用PROPAGATION_NESTEDӞ外层事务的回滚可以引起内层事务的回滚。而内层事务的异常q不会导致外层事务的回滚Q它是一个真正的嵌套事务。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTEDӞ需要JDBC 3.0以上驱动?.4以上的JDK版本支持。其它的JTA TrasactionManager实现可能有不同的支持方式?/p>
PlatformTransactionManagerQ?/span>
HibernateTransactionManager需要一?/span>SessionFactory的引?/span>
JtaTransactionManager
一Q把事务攄在了DAO层:
<!—hibernateTransactionManager-->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!—DAO层接口实?/span>-->
<bean id="companyDAOTarget"
class="com.vstsoft.querycompany.dao.impl.CompanyDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!—spring?/span>DAO层的事务代理-->
<bean id="companyDAOProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="companyDAOTarget" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="find*">
PROPAGATION_REQUIRED,readOnly
</prop>
</props>
</property>
</bean>
<!?span style="font-family: 宋体">业务层接口实玎ͼ?/span>DAO注入?/span>Service里面-->
<bean name="companyManageTarget"
class="com.vstsoft.querycompany.service.impl.CompanyManageTarget">
<property name="companyDAO">
<ref bean="companyDAOProxy" />
</property>
</bean>
<!—spring?/span>Service层的代理-->
<bean id="companyManageProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.vstsoft.querycompany.service.CompanyManage</value>
</property>
<property name="target">
<ref bean="companyManageTarget" />
</property>
</bean>
<!?span style="font-family: 宋体">配置
struts讉KQ把service层注入到action里面--><bean name="/company"
class="com.vstsoft.querycompany.web.action.CompanyAction" singleton="false">
<property name="companyManage">
<ref local="companyManageProxy" />
</property>
</bean>
二.把事务放|在?/span>Service层:
<!—jtaTransactionManager-->
<bean id="jtaTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager" />
<!—DAO层接口实?/span>-->
<bean id="companyDAOTarget"
class="com.vstsoft.querycompany.dao.impl.CompanyDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!—spring?/span>DAO层的代理-->
<bean id="companyDAOProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.vstsoft.querycompany.dao.CompanyDAO</value>
</property>
<property name="target">
<ref bean="companyDAOTarget" />
</property>
</bean>
<!?span style="font-family: 宋体">业务层接口实玎ͼ?/span>DAO注入?/span>Service里面-->
<bean name="companyManageTarget"
class="com.vstsoft.querycompany.service.impl.CompanyManageTarget">
<property name="companyDAO">
<ref bean="companyDAOProxy" />
</property>
</bean>
<!—spring代理业务层的事务理-->
<bean id="companyManageProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="jtaTransactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="set*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
<property name="target">
<ref bean="companyManageTarget" />
</property>
</bean>
<!?span style="font-family: 宋体">配置
struts讉KQ把service层注入到action里面--><bean name="/company"
class="com.vstsoft.querycompany.web.action.CompanyAction" singleton="false">
<property name="companyManage">
<ref local="companyManageProxy" />
</property>
</bean>
?/span>service层的接口实现CompanyManageImpl里面有个setDataҎQ按序执行数据查询Q数据删除,数据插入数据库行为,如果哪一步出异常Q运行时异常Q,事务回滚Q只有所有行为都没成功,事务提交?/span>
PlatformTransactionManager 直译q来是q_相关事务Q这里的q_指的?#8220;事务?#8221;Q包括刚才我说的DataSourceQjta{等。这些无一不是一个事务源。广义的_凡是可以完成事务性操作的对象Q都可以设计出相对应的PlatformTransactionManagerQ只要这个事务源支持commitQrollback 和getTransaction语意?
查看spring代码Q可以发现这些manager实现事务Q就是调用事务源的事务操作方?
比如
HibernateTransactionManager
java代码:
protected void doCommit(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Committing Hibernate transaction on session [" +
txObject.getSessionHolder().getSession() + "]";
}
try {
txObject.getSessionHolder().getTransaction().commit();
}
...
}
jdbc 的DataSourceTransactionManager
java代码:
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on connection [" + con + "]";
}
try {
con.commit();
}
...
}
那么PlatformTransactionManager以什么依据处理事务呢Q?
是TransactionStatus
查看api发现q个接口有三个方?
isNewTransaction() QisRollbackOnly()QsetRollbackOnly()
PlatformTransactionManager 是Ҏ前两个方法决定是否要创徏一个新事务Q是要递交q是回滚。至于第三个Ҏ是改变事务当前状态的Q很多地斚w要用刎ͼ偏偏 PlatformTransactionManager自n好像不怎么用,毕竟事务状态的改变是由E序员代码决定的Q不需要一个manager多管闲事?
ȝ上面所说的Qspring的事务由PlatformTransactionManager理Qmanager最后调用事务源的方法来实现一个事务过E。而manager通过TransactionStatus 来决定如何实现?
接下去说spring事务中的TransactionTemplate和TransactionInterceptor
TransactionTemplate 其实和spring中其他的template的作用类|起到化简代码的作用,不要被它那么长的名字吓倒了Q事实上q个templateq不是什么非常核心的对象。如果比较学I派的,可以ȝ看template设计模式Q在此就不再Ҏ赘述了?
Z么要有TransactionTemplateQ先来看看如果没有TransactionTemplateQ我们的代码该怎么?
先来看看spring reference中的一D代?
java代码:
DefaultTransactionDefinition def = new DefaultTransactionDefinition()
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
// execute your business logic here
} catch (MyException ex) {
transactionManager.rollback(status);
throw ex;
}
transactionManager.commit(status);
q是直接使用transactionManager的例子,可以看到真正执行business logic 的地Ҏ在try当中那段Q前后的代码都是Z完成事务理的。如果每个business logic都要写上那么一D,我肯定是疯了。我们翻出TransactionTemplate的代码看看他怎么化简了我们的代码
java代码:
public Object execute(TransactionCallback action) throws TransactionException {
TransactionStatus status = this.transactionManager.getTransaction(this);
Object result = null;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException ex) {
// transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Error err) {
// transactional code threw error -> rollback
rollbackOnException(status, err);
throw err;
}
this.transactionManager.commit(status);
return result;
}
同上面的代码如出一辙,前后是事务处理代码,当中那段result = action.doInTransaction(status);是我们的应用代码。至于action是什么,全看各位的需要了。但是有一点要主要Q如果利用TransactionTemplateQ那么他不管你扔Z么异帔R会回滚事务,但是回滚的是哪个事务呢?l箋挖代?
java代码:
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
if (logger.isDebugEnabled()) {
logger.debug("Initiating transaction rollback on application exception", ex);
}
try {
this.transactionManager.rollback(status);
}
catch (RuntimeException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
catch (Error err) {
logger.error("Application exception overridden by rollback error", ex);
throw err;
}
}
真相大白Q是对template所持有的某个transactionManagerq行回滚。所以如果你的应用代码用的是事务源a的一些资源,比如到服务器 a的一个datasourceQ但是你的transactionManager理的是另一些资源,比如服务器b的一个datasourceQ代码铁定不会正常运?
特别是在一些多事务源的E序里,q点千万不能搞错。如果多个事务源之间要完成全局事务Q还是老老实实用分布式事务管理服务吧QjtaQ?
那么TransactionInterceptor是干什么的Q这个是spring 的声明式事务的支持方式。因为用 TransactionTemplate要硬~码Q而且调整事务{略很麻烦(不是说不能调。D个例子原来程序抛出异常A需要回滚,现在不需要要Q我可以把a catch吃掉。这时候template׃会回滚了。但是每ơ调整都要重写编码。)而用TransactionInterceptor可以将q些调整写在配置中。我们再来挖TransactionInterceptor的代?
java代码:
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be null.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface
Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;
// Create transaction if necessary
TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);
Object retVal = null;
try {
// This is an around advice.
// Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceed();
}
catch (Throwable ex) {
// target invocation exception
doCloseTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
doFinally(txInfo);
}
doCommitTransactionAfterReturning(txInfo);
return retVal;
}
万变不离其宗?
所以用spring的事务管理需要作q些?
1Q设|好事务源,比如DataSourceQhibernate的session。如果有多个事务源要考虑他们之间是否有全局事务Q如果有Q老老实实用jtaQ否则就需要自己写一个manager?
2Q设|managerQ根据你的事务源选择对应的PlatformTransactionManager
3Q选择实现事物的方式,用templateq是interceptor。用template代码直观点,但是template所辖的manager和你应用代码所用的事务源要一致。如果用interceptor千万注意Q一定要调用interceptor那个beanQ而不是原始的那个target。在坛子上我已经看到臛_有两个朋友说spring事物不v作用Q从配置和代码上看都正确Q这时要好好查查Q调用的bean是哪一个?
4Q这个是设计问题了,推荐事务处于一个较高层ơ,比如service上的某个函数Q而底层的dao可以不考虑事务Q否则可能会出现事务嵌套Q增加程序复杂度?/p>
本来想xxAction调用父类的commonSaveҎ会DcommonManager为null的错误,因ؓjvmd始化BaseAction时ƈ不会L入CommonManger?
其实解决q个问题只需要在子类xxAction bean配置文g中加上commonManagerq个propertyQ然后把父类BaseAction的commonManager 改ؓprotected?Ok了。这样初始化子类的时候会注入commonManagerQ调用commonSaveҎ也就不会抛出npe了?/p>
配置文g中把xxAction 加上parent的配|也是可以的Q这样会把父cȝ所有property都注?/p>
public interface ApplicationContextAware {
/**
* Set the ApplicationContext that this object runs in.
* Normally this call will be used to initialize the object.
* <p>Invoked after population of normal bean properties but before an init callback such
* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
* {@link MessageSourceAware}, if applicable.
* @param applicationContext the ApplicationContext object to be used by this object
* @throws ApplicationContextException in case of context initialization errors
* @throws BeansException if thrown by application context methods
* @see org.springframework.beans.factory.BeanInitializationException
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
此方法被 ApplicationContextAwareProcessor ?postProcessBeforeInitialization 调用
ApplicationContextAwareProcessor implements BeanPostProcessor
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
return bean;
}