在新项目中偶然发现的问题:
1、spring的事务无全没用,在使用hibernate的保存方法那一句代码后,数据直接持久化到数据库,不管事务提交还是回滚,后面跟踪源码发现使用的JTA的事务环境,即分布式事务,但是jdbc事务并没有加入分布式事务中来管理,导致sql提交到mysql中后直接就保存了。
后面@Bean定义了一个JPA事务管理器,即强制使用这个。还有其他方法可以,删除分布式事务对应的包,或者在配置文件中加入spring.jta.enabled=false。还可以将事务加入jta中来管理。
2、在子项目中有个实体com.aa.AA对应一个表,在父项目中也有一个实体com.bb.AA对应同一个表,这两个实体的包路径不同,但是类名简称相同,在使用jpa的快捷查询findTopById时发生了实体类型转换错误,即com.aa.AA不能转换为com.bb.AA。findTopById生成的hql类似select aa from AA aa where aa.id=?1 ,hibernate 用一个map保存实体的映射关系,{com.aa.AA=com.aa.AA,AA=com.aa.AA}每个实体都会有两个key,一个全路径和一个简称。同理com.bb.AA也会有两个映射,所以AA作为key的键值对就会覆盖前一个,最终的结果可能是{com.aa.AA=com.aa.AA,AA=com.aa.AA,com.bb.AA=com.bb.AA}。
在将hql转换为sql时AA就会变成com.aa.AA。那在用com.bb.AA的findTopById时方法得到的就是com.aa.AA类型的,而方法返回值肯定是com.bb.AA类型的,所以就会出现类型转换失败。
其实在hibernate中都有这个问题。
最好的办法时修改实体名称,还有一种方法时在其中一个实体的注解@Entity上加入属性name,@Entity(name="xxx")这样之前的方法在生成hql时就变成select aa from xxx aa where aa.id=?1,hibernate中生成的实体映射也变成了{com.aa.AA=com.aa.AA,AA=com.aa.AA,com.bb.AA=com.bb.AA,xxx=com.bb.AA}。但是这样改的话还要当心,当有手动写的hql例如:update AA set name='';要把AA全部改成xxx才行,因为在hibernate中的map的key为AA对应的时其他的类了。
上面两个问题调试的关键在spring-tx包中的org.springframework.transaction.interceptor.TransactionAspectSupport类的invokeWithinTransaction方法。