关于spring事物控制加入try-catch后果的体会

    在项目中遇到了这样的问题,用户1上传知识文档,用户2、用户3等下载或者浏览对应知识文档,用户1增加相应积分,用户2、用户3扣除相应积分。

    目前问题是,文档正常下载,但是没有增加对应的积分,具体原因参见代码:

    1、事物控制通过注解,spring-context.xml文件

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

    2、控制层DocHandlerController

@RequestMapping(value = "/download", method = RequestMethod.GET)
@Params(params = {@Param(name = "id")})
@Permitted
public Object downloadById(RequestContext context, Subject<UserInfo> subject) throws IOException {
    String id = (String) context.getParam("id");
    return docDownloadService.downloadById(id, subject.getCurrentUserId(), context.getRequest());
}

    3、docDownServiceImpl,通过@Transactional进行注解控制,但要注意的是,try-catch部分没有继续抛出异常,事物控制在这一块无效。

@Transactional
    public Object downloadById(String id, String userId, HttpServletRequest request) {
        DocInfo docInfo = docInfoDao.get(new CompanyPK(id, CompanyIdThreadLocalUtil.get()));
        //改变总下载数
        docInfo.setDownloadNum(docInfo.getDownloadNum() + 1);
        //改变被别人下载数
        if (!userId.equals(docInfo.getCreateUserId())) {
            if (null != docInfo.getOthersDownloadNum()) {
                docInfo.setOthersDownloadNum(docInfo.getOthersDownloadNum() + 1);
            } else {
                docInfo.setOthersDownloadNum(1);
            }
        }

        docInfo = docInfoDao.update(docInfo);
        Integer othersDownloadNum = docInfo.getOthersDownloadNum();

        //当前用户不是发布用户,
        if (!userId.equals(docInfo.getCreateUserId())) {
            //判断当前用户是否下载过
            Boolean downloadRecord = (Boolean) WebServiceUtil.invokeLdsConnection(SystemConfigUtil.getAdminSystemUrl(request), "IntegralOutService", "validUserIsDownLoad", new Object[]{userId,
                    "isDownLoad", docInfo.getId(), CompanyIdThreadLocalUtil.get(), AskConstant.SYS_RULE_INTEGRAL_KNOWLEDGE
            });
            if (downloadRecord.booleanValue()) {

                if (DocConstant.SOURCES_FRONT.equals(docInfo.getSources())) {//学员端的知识才走积分接口
                    //未曾下载过
                    //知识被下载大于等于{}人次得{}分
                    IntegralRuleUtil.addIntegral(docInfo.getCreateUserId(), "knowledge_download", SysIntegralConstant.SYS_RULE_INTEGRAL_KNOWLEDGE, docInfo.getId(), CompanyIdThreadLocalUtil.get(), othersDownloadNum);
                }
                //文档下载积分大于0,才扣除积分
                if (docInfo.getIntegral() != null && docInfo.getIntegral() > 0) {
                    //积分接口调用(下载后扣除当前用户的积分)
                    IntegralRuleUtil.subtractIntegralByScore(userId, "isDownLoad", SysIntegralConstant.SYS_RULE_INTEGRAL_KNOWLEDGE, id, CompanyIdThreadLocalUtil.get(), docInfo.getIntegral());
                }
                if (DocConstant.SOURCES_FRONT.equals(docInfo.getSources())) {//学员端的知识才走积分接口
                    //上传文档者增加积分(设置的下载积分数)
                	IntegralRuleUtil.addIntegralByScore(docInfo.getCreateUserId(), "isDownLoad_add", SysIntegralConstant.SYS_RULE_INTEGRAL_KNOWLEDGE, docInfo.getId(), docInfo.getCompanyId(), docInfo.getIntegral());
                }
            }

        }
        try {
            return UploadUtil.downloadDoc(docInfo.getOriginalFile(), docInfo.getUploadName(), request);
        } catch (Exception e) {
            throw new ValidationException("文件不存在");
        }
    }

4、IntegralRuleUtil通过http调用积分接口

public static ResultMsg addIntegral(String userId,String ruleType,String businessCode,String businessId,String companyId,Integer number){
    String messageUrl = (String)SystemConfigUtil.getContextProperty("zxy.message.service.path");
    IntegralConfig integralConfig = new IntegralConfig(userId, ruleType, businessCode, businessId, companyId, messageUrl,number);
    return IntegralUtils.addIntegral(integralConfig);
}
public static ResultMsg addIntegral(IntegralConfig integralConfig) {
    try {
	Map<String, String> param = new HashMap<String, String>();
	param.put("integralConfig", JsonUtils.toJsonString(integralConfig));
	String jsonResult = HttpClientUtils.post(integralConfig.getUrl()+"/api/integral/add", param);
	return JsonUtils.jsonString2Bean(jsonResult, ResultMsg.class);
    } catch (Exception e) {
	logger.error("加积分接口调用异常,用户:" + integralConfig.getUserId() + ";积分类型:" + integralConfig.getRuleType(), e);
	return ResultMsg.getFailMsg("加积分接口调用失败,异常信息:"+e);
    }
}

    这里的http请求放到了try-catch中,由于项目部署时,端口配置错误,http调用接口失败,但是这里的异常被捕获了,使得事物失效,造成的结果是文档被下载n次,但是积分都没有。

    总结:如果是在事物中,最好不要使用try-catch。



Spring框架,你可以通过`@Transactional`注解或者`TransactionManagementConfigurer`接口来配置事务管理,以便在`try-catch`块更好地处理异常。这里是一些常见的做法: 1. **使用@Transactional注解**: - 在需要事务控制的方法上添`@Transactional`注解,可以指定传播行为(如PROPAGATION_REQUIRED表示默认行为,如果当前有事务,则加入;如果没有,新建一个)和隔离级别等。 ```java @Service @Transactional(rollbackFor = Exception.class) // 设置所有异常回滚 public class YourService { public void yourMethod() { try { // 业务代码 } catch (Exception e) { // 异常处理 } } } ``` 2. **基于配置类的方式**: 使用`TransactionDefinition`和`PlatformTransactionManager`来创建更复杂的事务规则。例如,在`applicationContext.xml`或`.java`配置文件定义事务管理器: ```xml <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 配置数据源 --> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> ``` 然后在代码里,你可以在`@Autowired`的`TransactionTemplate`或`JpaTransactionManager`上调用`execute`或`deferrableRead`等方法,手动管理事务。 3. **自定义异常处理器**: 可以通过实现`org.springframework.transaction.interceptor.TransactionInterceptor`并在`TransactionConfiguration`注册它,来处理特定类型的异常并决定是否回滚事务。 总之,Spring提供了一种灵活的方式来控制事务的边界和异常处理,你需要根据具体需求选择合适的配置方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值