异常解决org.apache.ibatis.type.TypeException: The alias ‘XXXX‘ is already mapped to the value ‘XXXX‘
一、错误主要错误:Caused by: org.apache.ibatis.type.TypeException: The alias ‘PoolInfo’ is already mapped to the value ‘com.XXX.PoolInfo’.当然还报了一些相关错误。二、背景代码中需要vo类封装内容,于是在com.XXX.vo包下建立了一个PoolInfo.java类,运行后发现项目
一、错误
主要错误:Caused by: org.apache.ibatis.type.TypeException: The alias ‘PoolInfo’ is already mapped to the value ‘com.XXX.PoolInfo’.
当然还报了一些相关错误。
二、背景
代码中需要vo类封装内容,于是在com.XXX.vo包下建立了一个PoolInfo.java类,运行后发现项目报错。报错日志显示之前已经在别的包中创建了一个名为PoolInfo.java的类。也就是我在不同的包中创建相同的类名会报错,java编译使用的是全限定类名,所以编译能通过。
三、分析
根据报错日志可以看出出错的地方是和mybatis相关的,然后查看数据源的配置类果然发现了问题,关键代码如下
// CoreDataSourceConfig.java
@Bean(name = "coreSqlSessionFactory")
@Primary
public SqlSessionFactory coreSqlSessionFactory(@Qualifier("coreDataSource") DataSource coreDataSource) throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setTypeAliasesPackage("com.XXX");
sessionFactory.setVfs(SpringBootVFS.class);
sessionFactory.setDataSource(coreDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(CoreDataSourceConfig.MAPPER_LOCATION));
return sessionFactory.getObject();
}
代码中第六行sessionFactory.setTypeAliasesPackage(“com.XXX”);看源码的注释这个字段的作用是“Packages to search for type aliases.”会根据配置的路径用于搜索类型别名的包。再看源码,主要代码如下
// org/apache/ibatis/type/TypeAliasRegistry.java 部分代码
public void registerAliases(String packageName, Class<?> superType){
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for(Class<?> type : typeSet){
// Ignore inner classes and interfaces (including package-info.java)
// Skip also inner classes. See issue #6
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
registerAlias(type);
}
}
}
public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}
public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
String key = alias.toLowerCase(Locale.ENGLISH);
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
TYPE_ALIASES.put(key, value);
}
从源码中可以看出,它是先根据路径取到所有的类,然后判断是否有@Alias注解,如果有就用注解中的名字,没有就用类名当做别名。
因此是代码中的路径(“com.XXX”)写的太大,包含了整个项目的类并且类中没有@Alias注解进行区分名字,导致运行项目时找到了相同的别名,抛出了异常(第二个代码框中第31行)。
四、解决
有以下三种方法:
- 设置类型别名的路径时可以具体到实体类,多个包下的实体类可以同逗号分隔。sessionFactory.setTypeAliasesPackage(“com.aaa.bbb.entity, com.aaa.ccc.entity”);
- 在具有相同类名的类上使用@Alias(“XXX”)注解,注解中的字符串设置为不同值。注意:mybatis会把类设置成注解中的别名。
- 把相同的类名修改为不同的类名。
更多推荐
所有评论(0)