以上代码完成数据写入数据库的操作。
其向外提供生成代理对象的函数getMapper()方法如下:
public T getMapper(Class type, SqlSession sqlSession) {
//如果不存在这个mapper,则直接抛出异常
if (!knownMappers.contains(type))
throw new BindingException(“Type " + type + " is not known to the MapperRegistry.”);
try {
//返回代理类
return MapperProxy.newMapperProxy(type, sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
MyBatis中涉及到ORM的思想,ORM框架最重要功能是将面向对象方法中的对象和关系型数据库中的表关联了起来,在关联过程中就必然涉及到对象中的数据类型(Java数据类型)和数据库中的表字段类型的转换,Mybatis中的org.apache.ibatis.type包主要就是实现这个功能。只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。当前ORM框架主要有三种:Hibernate,iBATIS,EclipseLink。
映射关系体现在mapper文件中,有两种方式进行关联,分别是:基于注解的方式和编写映射文件(xml)的形式。基于注解的形式如下:
public interface UserMapper {
@Select(value=“select * from user where id = #{id}”)
public User findUserById(int id);
@Select(value=“select * from user where username = #{username} and password = #{password}”)
public User login(User user);
@Insert(value=“insert into user (id,username,phone,email,password) values(#{id},#{username},#{phone},#{email},#{password})”)
public void insertUser(User user);
@Select(value=“select * from user where nickname = #{nickname} and email = #{email}”)
public User findUserByNameAndEmail(User user);
}
以插入操作为例,插入的数据为#{id}...其属性为domain域中类的相关属性。框架会在属性中进行相应属性的查找。若查找不到则会报错。
public class SqlSessionUtils {
/**
- SqlSessionFactory对象可以看成DataSource(数据库连接池)
- 在应用执行期间,应该只创建一次,建议使用单例模式
*/
private static SqlSessionFactory factory=null;
public static SqlSessionFactory getSessionFactory(){
if(factorynull){
synchronized (SqlSessionUtils.class) {
if(factorynull){
try {
//1.创建配置文件的输入流
String resource = “mybatis.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
//2.创建SqlSessionFactory
factory=new SqlSessionFactoryBuilder().build(inputStream);
//添加映射器类(注解方式),避免了对xml文件的依赖
factory.getConfiguration().addMapper(MyLotteryMapper.class);
factory.getConfiguration().addMapper(LotteryMapper.class);
factory.getConfiguration().addMapper(UserMapper.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
return factory;
}
}
在使用ibatis执行数据库访问时,会调用形如
getSqlMapClientTemplate().queryForObject("getCityByCityId", cityId);
这样的代码。这样的形式要求调用方选择需要使用的函数(queryForObject、queryForList、update),还需要告诉这个函数具体执行哪一个statement(上文中是“getCityByCityId”),在这个过程中如果有一个地方选择错误或者拼写错误,不仅没有办法达到自己的期望值,可能还会出现异常,并且这种错误只有在运行时才能够发现。
mybatis对此进行了改进,只要先声明一个接口,就可以利用IDE的自动完成功能帮助选择对应的函数,简化开发的同时增加了代码的安全性。(如以下接口UserMapper所示 )
public interface UserMapper { @Select(value=“select * from user where id = #{id}”) public User findUserById(int id); @Select(value=“select * from user where username = #{username} and password = #{password}”) public User login(User user); @Insert(value=“insert into user (id,username,phone,email,password) values(#{id},#{username},#{phone},#{email},#{password})”) public void insertUser(User user); @Select(value=“select * from user where nickname = #{nickname} and email = #{email}”) public User findUserByNameAndEmail(User user); }
以下为MapperRegistry中addMapper方法的底层代码:
public void addMapper(Class<?> type) { //因为Java的动态代理只能实现接口,因而在注册mapper时也只能注册接口 if (type.isInterface()) { //如果已经注册过了,则抛出异常,而不是覆盖 if (knownMappers.contains(type)) { throw new BindingException(“Type " + type + " is already known to the MapperRegistry.”); } boolean loadCompleted = false; try { //先将这个mapper添加到mybatis中,如果加载过程中出现异常需要再将这个mapper从mybatis中删除 knownMappers.add(type); // It’s important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. If the type is already known, it won’t try. //下面两行代码其实做了很多的事,由于涉及的东西较多,在此不做过多的描述,留待以后专门进行介绍 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }
[![image](https://img-blog.csdnimg.cn/img_convert/cbca7f272b20bf912b39ceb2c8af2b44.png)](http://images.cnitblog.com/blog/330894/201305/13153904-5a35cac9ed584ecfb2f5d9e87b336315.png)
另外,MyBatis持久层框架还涉及到动态绑定、反射、单例、工厂设计模式。个人感觉,应深入到底层代码去阅读,只有这样才可以对框架有进一步的了解。
### 参考网址
http://www.th7.cn/Program/java/201407/240933.shtml [http://www.th7.cn/Program/java/201407/240933.shtml](https://bbs.csdn.net/topics/618166371)
http://blog.csdn.net/hupanfeng/article/details/9238127 [http://blog.csdn.net/hupanfeng/article/details/9238127](https://bbs.csdn.net/topics/618166371)
mybatis源代码分析之binding包
http://www.cnblogs.com/sunzhenchao/archive/2013/05/13/3075854.html <http://www.cnblogs.com/sunzhenchao/archive/2013/05/13/3075854.html>
Mybatis源代码分析之别名
<http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3010527.html>
动态代理 反射机制
**这里分享一份由字节前端面试官整理的「2021大厂前端面试手册」,内容囊括Html、CSS、Javascript、Vue、HTTP、浏览器面试题、数据结构与算法。全部整理在下方文档中,共计111道**
### HTML
* HTML5有哪些新特性?
* Doctype作⽤? 严格模式与混杂模式如何区分?它们有何意义?
* 如何实现浏览器内多个标签页之间的通信?
* ⾏内元素有哪些?块级元素有哪些? 空(void)元素有那些?⾏内元 素和块级元素有什么区别?
* 简述⼀下src与href的区别?
* cookies,sessionStorage,localStorage 的区别?
* HTML5 的离线储存的使用和原理?
* 怎样处理 移动端 1px 被 渲染成 2px 问题?
* iframe 的优缺点?
* Canvas 和 SVG 图形的区别是什么?
![](https://img-blog.csdnimg.cn/img_convert/476288e164f5711c5c11e55a79185bd8.png)
### JavaScript
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**
* 问:0.1 + 0.2 === 0.3 嘛?为什么?
* JS 数据类型
* 写代码:实现函数能够深度克隆基本类型
* 事件流
* 事件是如何实现的?
* new 一个函数发生了什么
* 什么是作用域?
* JS 隐式转换,显示转换
* 了解 this 嘛,bind,call,apply 具体指什么
* 手写 bind、apply、call
* setTimeout(fn, 0)多久才执行,Event Loop
* 手写题:Promise 原理
* 说一下原型链和原型链的继承吧
* 数组能够调用的函数有那些?
* PWA使用过吗?serviceWorker的使用原理是啥?
* ES6 之前使用 prototype 实现继承
* 箭头函数和普通函数有啥区别?箭头函数能当构造函数吗?
* 事件循环机制 (Event Loop)
![](https://img-blog.csdnimg.cn/img_convert/0ba8bcdea9cbbc7373d2fa90b1951a07.png)