精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2004-12-27
<bean id="xxxService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="target"><ref local="applicationServiceTarget"/></property> <property name="transactionAttributes"> <props> <prop key="xxxMethod">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="xxxServiceTarget" class="com.nosqldb.service.spring.XXXServiceImpl"> </bean> 以下是我对spring容器管理的事务的总结,对错否望指正。[list] 1.spring容器管理的事务是自动回滚的,也就是被纳入事务管理的类的函数执行完毕,事务自动提交。大家可能会想:假如函数调用发生异常,事务会自动回滚。不完全对!函数只有抛出派生自java.lang.RunTimeException这种类型的异常才能回滚事务(本人建议将其派生自org.springframework.dao.DataAccessException)。而且只能回滚对数据库的操作,而不能回滚其它类型的操作(比如,已经发送出去的email就不能“回滚”)。所以,要正确地回滚一个混和数据库操作和其它类型操作(例如发送Email操作)的事务,只能把其它类型的操作放在最后。例如把发送email的操作放在数据库操作的后面,发送email发生异常,数据库操作自动回滚--email的发送当然也不成功。假如用数据库操作的异常回滚一个email的发送,那是不可能的。还有对于email的发送异常应该进行这样的封装(注意以下语句:throw new SendEmailException): public class MailServiceSpringImpl implements IMailService { protected final Log logger = LogFactory.getLog(getClass(););; private String smtpMailHost; private String smtpMailUsername; private String smtpMailPassword; private String transport; public void sendEmail(String from, String[] to, String subject, String text); { Properties props = new Properties();; Session session; Store store; Transport t; session = Session.getInstance(props, null);; props.put("mail.smtp.host", this.getSmtpMailHost(););; props.put("mail.smtp.username", this.getSmtpMailUsername(););; props.put("mail.smtp.password", this.getSmtpMailPassword(););; Message msg = new MimeMessage(session);; try { msg.setFrom(new InternetAddress(from););; msg.setSubject(subject);; msg.setSentDate(new Date(););; msg.setText(text);; t = session.getTransport(this.getTransport(););; t.connect();; if (to != null && to.length > 0); { for (int i = 0; i < to.length; i++); { Address address = new InternetAddress(to[i]);; msg.setRecipient(Message.RecipientType.TO, address);; t.send(msg);; } } t.close();; } catch (Exception e); { logger.error("Send Email Exception--", e);; throw new SendEmailException();; } } public void sendEmail(String fromAddress, String toAddress, String subject, String text); { this.sendEmail(fromAddress, new String[] { toAddress }, subject, text);; } public String getSmtpMailHost(); { return smtpMailHost; } public String getTransport(); { return transport; } public void setTransport(String transport); { this.transport = transport; } public void setSmtpMailHost(String smtpMailHost); { this.smtpMailHost = smtpMailHost; } public String getSmtpMailPassword(); { return smtpMailPassword; } public void setSmtpMailPassword(String smtpMailPassword); { this.smtpMailPassword = smtpMailPassword; } public String getSmtpMailUsername(); { return smtpMailUsername; } public void setSmtpMailUsername(String smtpMailUsername); { this.smtpMailUsername = smtpMailUsername; } } 其中的SendEmailException派生自org.springframework.dao.DataAccessException,是用来回滚数据库操作的事务的。 2.org.springframework.dao.DataAccessException是RuntimeException,可以捕捉,也可以不捕捉;可以在函数后面的throws声明抛出这种类型的异常,也可以不声明。本人的建议:对这种类型的异常,可以声明,但不捕捉--这样函数调用可以一步运行到底,省去好多的try和catch。在controller层不用捕捉,除非你使用这些异常给controller传递信息从而控制页面的跳转。 3.对于不捕捉的异常,spring容器会自动捕捉(当然也会自动回滚事务),并自动地跳转到相应的异常页面,例如(异常处理也有优先级): <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.springframework.transaction.TransactionException">dataAccessException.jsp</prop> <prop key="org.ggyy.service.exception.AuthorizationDenyException">authorizationException.jsp</prop> <prop key="org.ggyy.service.exception.NotLoginException">notLoginException.jsp</prop> <prop key="org.springframework.dao.DataAccessException">dataAccessException.jsp</prop> <prop key="java.lang.Exception">systemException.jsp</prop> </props> </property> </bean> 使用这种方式给人的感觉就是:Service层和View层是直接通讯的,也就是Service层使用不同的异常类型控制jsp页面的跳转(当然只是异常跳转),而controller只是把程序一步运行到底,出了异常跳转到哪个页面也不知道。 [/list:u] 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-12-27
那么如果只是抛出不捕捉,那程序怎么知道,事务是成功完成了呢?还是失败了被回滚了呢?
对这一点,尤其是声明性事务,如何在程序中判断事务的结果呢? |
|
返回顶楼 | |
发表时间:2004-12-27
程序(一般指controller)运行结束,没发生异常,就自动地提交一个声明的事务。出现异常(是指派生自DataAccessException)除了自动回滚一个事务外,还自动跳转到相应的出错页面(事务运行的结果是不言自明的),出错页面由一个spring 的bean解析:
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.springframework.transaction.TransactionException">dataAccessException.jsp</prop> <prop key="org.ggyy.service.exception.AuthorizationDenyException">authorizationException.jsp</prop> <prop key="org.ggyy.service.exception.NotLoginException">notLoginException.jsp</prop> <prop key="org.springframework.dao.DataAccessException">dataAccessException.jsp</prop> <prop key="java.lang.Exception">systemException.jsp</prop> </props> </property> </bean> 比如,org.ggyy.service.exception.NotLoginException和NotLoginException.jsp相对应,NotLoginException.jsp代码如下: <%@ page contentType="text/html; charset=gb2312"%> <%@ include file="includes.jsp"%> <HEAD> </HEAD> <BODY> <TABLE width="780" height=300 border="0" cellspacing="0" cellpadding="0" > <% Exception ex = (Exception); request.getAttribute("exception");; %> <H2>没登陆: <%= ex.getMessage(); %></H2> <p> <% ex.printStackTrace(new java.io.PrintWriter(out););; %> <P> <BR> 在这个jsp里面,你能取得spring容器抛出的exception也就是你在Service层抛出的那个exception,你可以将其转换为你所抛出的那个异常,然后想打印什么样的信息都可以。 对于这类的异常(DataAccessException),spring 也不建议捕捉,spring的XXXDaoSupport还把大量的异常封装到DataAccessException,还向我们表明:不写try 和catch和finally是很酷的编程方式。例如: public void store(Entity entity); throws DataAccessException { this.getHibernateTemplate();.saveOrUpdate(entity);; } 假如使用HibernateSession的openSession,beginTransaction,endTransaction等等,try和catch和finally肯定要写的。 |
|
返回顶楼 | |
发表时间:2004-12-29
大愚弱智 写道 函数只有抛出派生自org.springframework.dao.DataAccessException这种类型的异常才能回滚事务。
非也非也,理解错误。建议自定义异常做个测试,一试便知。 |
|
返回顶楼 | |
发表时间:2004-12-30
我敢用一生的运气担保:
public class ManagerServiceImpl implements IManagerService { private ICatDao catDao; /** * 一个声明式事务 */ public void testTransaction();throws Exception { Cat cat=new Cat();; this.getCatDao();.store(cat);; throw new Exception();; } public ICatDao getCatDao(); { return catDao; } public void setCatDao(ICatDao catDao); { this.catDao = catDao; } } public class ManagerServiceTest extends TestCase { public void testAll();{ IManagerService service = (IManagerService);ServiceFactory.getApplicationContext();.getBean("managerService");; try { service.testTransaction();; } catch (Exception e); { e.printStackTrace();; } } } <bean id="managerService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="target"><ref local="managerServiceTarget"/></property> <property name="transactionAttributes"> <props> <prop key="testTransaction">PROPAGATION_REQUIRED</prop> </props> </property> </bean> 结果数据库还是增加了一条记录,证明事务没有回滚。 |
|
返回顶楼 | |
发表时间:2004-12-30
试试看RuntimeException
http://www.springframework.org/docs/api/org/springframework/transaction/interceptor/RuleBasedTransactionAttribute.html TransactionAttribute implementation that works out whether a given exception should cause transaction rollback by applying a number of rollback rules, both positive and negative. If no rules are relevant to the exception, it behaves like DefaultTransactionAttribute (rolling back on runtime exceptions). btw, 一生的运气...... |
|
返回顶楼 | |
发表时间:2004-12-30
大愚弱智 写道 我敢用一生的运气担保:
这句话应该理解为:我只担保我贴出来的这个程序不会回滚事务^_^。 看了一下spirng的源代码,DataAccessException源自RuntimeException。RuntimeException和Exception有什么不同我不了解,惭愧! |
|
返回顶楼 | |
发表时间:2004-12-30
大愚弱智 写道 大愚弱智 写道 我敢用一生的运气担保:
这句话应该理解为:我只担保我贴出来的这个程序不会回滚事务^_^。 狡猾狡猾滴,那么把你最开始的文章修改正确吧。 |
|
返回顶楼 | |
发表时间:2005-01-30
ReadOnly落井下石啊...
|
|
返回顶楼 | |
发表时间:2005-01-31
Readonly 写道 大愚弱智 写道 大愚弱智 写道 我敢用一生的运气担保:
这句话应该理解为:我只担保我贴出来的这个程序不会回滚事务^_^。 狡猾狡猾滴,那么把你最开始的文章修改正确吧。 怕了你,我改就是了。 |
|
返回顶楼 | |