MyBatis中Mapper接口映射到数据库原理分析
来源:互联网 发布:金隅悦城丽悦园网络 编辑:程序博客网 时间:2024/06/07 01:34
刚学习MyBatis,对于用@Mapper注解的接口能够完成POJO对象到数据库记录映射百般疑惑,一开始很纳闷为什么不需要定义Mapper接口的实现类就能完成这个过程。例如以下代码段中只定义了UserDAO这个接口,但是并不影响POJO对象到数据库的映射。查阅了相关的资料,稍有解惑。
@Mapperpublic interface UserDAO { String TABLE_NAME = "user"; String INSERT_FIELDS = "name, password, salt, head_url"; String SELECT_FIELDS = "id, name, password, salt, head_url"; @Insert({"insert into", TABLE_NAME, "(", INSERT_FIELDS, ") values(#{name}, #{password}, #{salt}, #{headUrl})"}) int addUser(User user);}public class InitDBTest {@AutowiredUserDAO userDAO;public void contextLoads() {User user = new User();user.setName("user1");user.setPassword("");user.setSalt("");user.setHeadUrl("xxx.png");userDAO.addUser(user);}}
1. MapperRegistry
程序启动之初MyBatis就创建了这个类的一个实例,它有一个HashMap类型的属性用于存储每个Mapper接口(key)和相应的MapperProxyFactory(value);另外有两个重要的方法getMapper()和addMapper(),分别用于获取和注册Mapper接口到这个HashMap中。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type); if(mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } else { try { return mapperProxyFactory.newInstance(sqlSession);//通过Mapper接口的type返回一个相应的mapperProxyFactory的一个实例 } catch (Exception var5) { throw new BindingException("Error getting mapper instance. Cause: " + var5, var5); } } }public <T> void addMapper(Class<T> type) { if(type.isInterface()) { if(this.hasMapper(type)) { throw new BindingException("Type " + type + " is already known to the MapperRegistry."); } boolean loadCompleted = false; try { this.knownMappers.put(type, new MapperProxyFactory(type));//将这个Mapper接口“注册” MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type); parser.parse(); loadCompleted = true; } finally { if(!loadCompleted) { this.knownMappers.remove(type); } } } }
2. MapperProxyFactory
正如它的名字mapper代理工厂“,这个类是一个生产mapper代理对象的工厂,而mapper代理对象负责代替mapper接口完成POJO到数据库的映射。在MapperProxyFactory中的两个重要方法如下,用于创建mapper代理类的一个实例。
protected T newInstance(MapperProxy<T> mapperProxy) {//用了java的动态代理,获得真正的代理对象 return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); }public T newInstance(SqlSession sqlSession) { MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); return this.newInstance(mapperProxy); }
3. MapperProxy
通过调用特定的mapper代理对象的invoke()方法,实现到数据库的映射,实际上invoke()中又调用了MapperMethod中的execute方法,execute方法主要是用到sqlSession的insert、update、select、delete等,这部分就是我们都很熟悉的了。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } } else { MapperMethod mapperMethod = this.cachedMapperMethod(method); return mapperMethod.execute(this.sqlSession, args); } }
4. MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) { Object param; Object result; if(SqlCommandType.INSERT == this.command.getType()) { param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.insert(this.command.getName(), param)); } else if(SqlCommandType.UPDATE == this.command.getType()) { param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.update(this.command.getName(), param)); } else if(SqlCommandType.DELETE == this.command.getType()) { param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.delete(this.command.getName(), param)); } else if(SqlCommandType.SELECT == this.command.getType()) { if(this.method.returnsVoid() && this.method.hasResultHandler()) { this.executeWithResultHandler(sqlSession, args); result = null; } else if(this.method.returnsMany()) { result = this.executeForMany(sqlSession, args); } else if(this.method.returnsMap()) { result = this.executeForMap(sqlSession, args); } else if(this.method.returnsCursor()) { result = this.executeForCursor(sqlSession, args); } else { param = this.method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(this.command.getName(), param); } } else { if(SqlCommandType.FLUSH != this.command.getType()) { throw new BindingException("Unknown execution method for: " + this.command.getName()); }
回到最上面的demo,userDAO属性被注解为@Autowired,由spring完成bean的自动装配,其中spring会去获取一个MyBatis的mapperProxy代理对象作为这个bean,它是一个真正的对象而不是一个Interface类型,由这个代理人完成到数据库的映射。
阅读全文
0 0
- MyBatis中Mapper接口映射到数据库原理分析
- [Mybatis] Mapper接口原理分析
- Mybatis中Mapper映射
- MyBatis中通过Mapper接口加载映射文件
- MyBatis Mapper接口实现原理
- Mybatis续、Mapper映射器接口规则
- mybatis mapper映射文件参数填充原理
- Mybatis中Mapper映射文件详解
- mybatis mapper 接口原理(mybatis 注解原理)
- Mybatis--使用mybatis generator插件映射数据库,自动生成pojo对象,dao接口,mapper.xml文件的方法
- Java的MyBatis框架中Mapper映射配置的使用及原理解析
- Java的MyBatis框架中Mapper映射配置的使用及原理解析
- MyBatis框架核心之(二)Mapper配置文件使用接口映射
- Mybatis(Mapper映射开发)
- Mybatis入门到精通-Mapper映射器模式
- Mybatis配置和接口映射原理
- Mybatis配置和接口映射原理
- mybatis中一对多映射mapper.xml文件
- VMWarevSphere Client 克隆虚拟机、变更IP地址、变更主机名、修改MAC地址
- 逆序输出字符串
- hive管理之命令行方式CLI
- maven 构建项目时 java路径下配置属性文件相关
- 求职准备428
- MyBatis中Mapper接口映射到数据库原理分析
- android studio编译速度过慢的解决办法。
- printf 函数实现的深入剖析[转载]
- JavaEE之Struts2获取表单数据
- Linux 守护进程的原理与实现
- squid
- TCP/UDP端口列表
- 自力更生打造自己的个人网站,开袋即食
- 关闭迅雷首页自动播放视频