由于发现爬商品信息的几个网站时,发现它曾经推荐过的商品会忽略时间排序方式跑到前面去,有些推荐过的商品可能会被删除,这就给爬取算法带来了很大的困难。如果不妥善处理这个问题,可能会有很多重复商品信息,给后续商品展示带来了很大的困扰。所以给goods表中添加了唯一约束,添加列为商品所属网站和在网站的ID。
- alter table goods
- add constraint unique(category,categoryid)
原设想是在service中新添加商品时如果与之前表中已有数据有冲突,就会跳过这一项,处理下一条商品添加。但首先碰到的困难是,会因为违反唯一约束抛出异常所以无法添加相关商品,可是List中后续商品都不会执行添加操作,报的异常是“don't flush the Session after an exception occurs”,这是因为aop不管有没有异常都会执行flush操作。
所以我的解决方案最初是在dao类中添加try,catch希望能捕获异常,然后将当前transaction回滚。
但会抛出异常“Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started”,这是因为transaction已经结束,就无法执行aop中的commit操作。
后来查资料,发现spring的transactionManager默认只对RuntimeException异常回滚。 (如果是非运行时异常只能在aop的tx:method中添加rollback-for="*Exception")后在service方法里添加 throws ConstraintViolationException这样就会发现异常时主动回滚。必须要在service的方法里抛出,因为这样aop才能检测得到,不然光try catch,spring还是不知道异常。
又碰到了另外一个问题。在排查为什么会出现这些冲突的时候,发现有些信息是会改变的,那可以做一个更新的功能,每次捕捉到ConstraintViolationException异常时,必须要抛出,因为要让事务回滚,但是同时可以执行更新操作。又重温了一下hibernate的基本操作 ,http://www.blogjava.net/dreamstone/archive/2007/07/29/133071.html
同时还要注意爬商品信息的算法,其中的recentCategoryId只能是新添加的商品id,不能是修改的商品的id