记录项目热启动,mysql操作异常
1.配置热启动后,发现修改代码后,项目没有热启动
最后发现:热启动依赖HotSwap,目前HotSwap只支持对方法体修改,不支持对类和方法签名的修改(比如类名,方法名,方法参数等)。大概是依赖签名替换覆盖class文件
2.之前一直说事务注解,加的的时候,要指定为@Transactional(rollbackFor = Exception.class),不然除了运行时异常,其他异常事务不能回滚,比如SqlException(继承Exception)语句出错。今天专门试了一下mysql的异常(框架不同,异常可能不同)(com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'd.cmc_declare_status2' in 'field list'),故意写错字段名,却发现事务回滚了,又去看了MySQLSyntaxErrorException确实继承SqlException类。为此感到惊喜,记录一下。(另同事说不是运行时异常RuntimeException,再编译的时候就会报错)
注意:这里说明一下,上面的非运行异常为什么会导致事务回归。下图也是故意写过字段抛出的错误
查找关系,java.sql.SQLSyntaxErrorException是非运行异常,但是事务回滚了(使用的注解为@Transactional),是不是说明非运行异常在注解@Transactional的作用下也会回滚呢,这显然和官网说的只回滚运行异常和error有出入。
经debug和看异常日志发现了问题。之前看异常日志只觉得Cause一行有用,at之类的语句都忽略了,这里请看上图框中的内容,对应的源码是CustomSQLErrorCodesTranslation
debug也发现,抛出java.sql.SQLSyntaxErrorException后,也会走到这里来,这里重新把异常封装了一次org.springframework.jdbc.BadSqlGrammarException,经查找,发现这个异常是RuntimeException的子类。所以异常回滚了
这里暂时不知道异常消息日志没打印,可能和日志级别有关
另:InvocationTargetException(反射异常)也没看出来:当被调用的方法的内部抛出了异常而没有被捕获时,将由此异常接收。
3.并行流parallelStream,看了几篇文章(比如:https://blog.csdn.net/Tianzijiang0306/article/details/85140319,https://blog.csdn.net/qq_31840023/article/details/100579117),说解决线程安全问题。情况是对集合的并行流中,进行一些包含第三方对象的操作(第三方对象:共享变量),问题是:共享变量不是线程安全的或者操作共享变量的方法不是线程安全的,结果是:得到的结果可能不对或是运行报错,比如如果第三方对象是集合,会报溢出异常。
但是:这是多线程操作共享变量没加锁导致的问题,不是parallelstream的问题,而且,使用流操作时,又是会提示传进去的参数,应是final的(Variable used in lambda expression should be final or effectively final),比如:
并行流本身没有问题,测过。
4.ForkJoinTask使用记录:
1 private static ForkJoinPool pool = new ForkJoinPool(20); 2 private ResponseHolder updateDetailOrderStatus(List<String> idList, String type, Integer status) { 3 String messageFormat = "单号修改成功%d单,失败%d单。"; 4 try { 5 ForkJoinTask<Integer> task = pool.submit(() -> { 6 Integer integer = Lists.partition(idList, systemConfigService.getOrderStausEditRow()).parallelStream() 7 .map(subList -> { 8 //处理逻辑,返回修改单数 9 try { 10 return outDeclareCoreService.doDealStatus(subList, type, status); 11 }catch (Exception e){ 12 logger.error("修改订单状态时发生系统错误", e); 13 return 0; 14 } 15 }).reduce(Integer::sum).get(); 16 return integer; 17 }); 18 Integer count = task.get(); 19 String message = String.format(messageFormat, count, idList.size() - count); 20 return ResponseHolder.buildSuccessResponse().message(message); 21 } catch (Exception e) { 22 logger.error("申报单修改状态发生异常",e); 23 throw new BusinessException("系统异常"); 24 } 25 }
outDeclareCoreService.doDealStatus有事务,systemConfigService.getOrderStausEditRow()是按多少分片,代码意思是,对数据进行分组后,异步处理这些数据,并得到成功数量,如果异步线程错误,返回0条,最后通过 task.get()获得最终结果。
代码发布后,同事使用1w单测试,没有问题,我测试,却报错:task.get() noSuchElementException,Option.get,网上看了很多ForkJoinTask的讲解,是有个异常ExecutionException,但并非是我这种情况。task.get()会等待线程结束然后获取结果,暂时没发现我错误的原因。
今天又试了一次,同样的情况,却成功了,真的是郁闷。特此记录。
5.xml2obj错误记录:
xml有namespace,转java时,报错,遇到uri(namespace的值)
参看:
https://www.icode9.com/content-1-242854.html
JAXB & Namespaces:http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
XML序列化,添加命名空间,添加声明头,添加节点前缀:https://www.cnblogs.com/zfylzl/p/5653432.html