mybatis 可以通过动态代理实现mapper。其中Mapper类和Mapper.xml必须要放在一起。
sqlMapConfig.xml的配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<!-- 别名 包以其子包下所有类 头字母大小都行-->
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url"
value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- Mapper的位置 Mapper.xml 写Sql语句的文件的位置 -->
<mappers>
<!-- <mapper resource="sqlmap/User.xml" class="" url=""/> -->
<!-- <mapper resource="sqlmap/User.xml" class="" url=""/> -->
<!-- <mapper class="com.itheima.mybatis.mapper.UserMapper" /> -->
<!-- <mapper url="" /> -->
<package name="com.mapper"/>
</mappers>
</configuration>
其中mapper.xml 配置在类的所在目录。
其中解析文件时有这样的代码
private void loadXmlResource() {
// Spring may not know the real resource name so we check a flag
// to prevent loading again a resource twice
// this flag is set at XMLMapperBuilder#bindMapperForNamespace
//type.getName()的值为 com.mapper.TestMapper
if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
// xmlResource 的值为 com/mapper/TestMapper.xml
String xmlResource = type.getName().replace('.', '/') + ".xml";
InputStream inputStream = null;try {
inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
} catch (IOException e) {
// ignore, resource is not required
}
if (inputStream != null) {
XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
xmlParser.parse();
}
}
}
执行操作时进入的源代码:
//proxy 是代理生成的类 method 调用的方法 args参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
Class<?> declaringClass, Configuration configuration) {
//获取mapper.xml中id 可以看出来 通过 接口类的名称 + 方法名 和参数无关 所以mapper 里面的方法 不能重载
//如果重载了 在解析配置文件时 就会报 Mapped Statements collection already contains value for 、com.mapper.TestMapper.deleteByPrimaryKey 错误信息。
if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
} else if (mapperInterface.equals(declaringClass)) {
return null;
}
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
if (declaringClass.isAssignableFrom(superInterface)) {
MappedStatement ms = resolveMappedStatement(superInterface, methodName,
declaringClass, configuration);
if (ms != null) {
return ms;
}
}
}
return null;
}
}