Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 381|回复: 0

[默认分类] MyBatis进阶(一)运行原理

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-5-28 16:55:11 | 显示全部楼层 |阅读模式


           初次学习MyBatis,自己花了不少时间,理解一件事物是需要时间的。经过多次反复的理解,你的认知能力就可以得到提升。以下是学习MyBatis的一些理解认识,技术理解上若有不当之处,敬请朋友们提出宝贵意见,以此共勉!
          感触:要想真正理解框架,应该深入到底层实现代码中去。只有这样,才能够真正理解其框架内涵,或许还可以写出个性化的框架喲!
          基本的演变流程为:JDBC--->dbutils--->MyBatis--->Hibernate
           MyBatis作为数据库持久层框架,在使用前首先导入相关jar包(mybatis-3.2.7.jar),还要对其进行配置,配置文件为mybatis.xml,

    1. <?xml version="1.0" encoding="UTF-8" ?>
    2. <!DOCTYPE configuration
    3.   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    4.   "http://mybatis.org/dtd/mybatis-3-config.dtd">
    5. <configuration >
    6. <properties resource="jdbc.properties" />
    7. <!-- 设置信息元素
    8.   会修改MyBatis在运行时的行为方式 -->
    9.   <settings>  
    10.                 <!-- 全局映射器启用缓存 -->  
    11.         <setting name="cacheEnabled" value="true" />  
    12.                 <!-- 查询时,关闭关联对象及时加载以提高性能 -->  
    13.         <setting name="lazyLoadingEnabled" value="true" />  
    14.                 <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指定),不会加载关联表的所有字段,以提高性能 -->  
    15.         <setting name="aggressiveLazyLoading" value="false" />  
    16.                 <!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->  
    17.         <setting name="multipleResultSetsEnabled" value="true" />  
    18.                 <!-- 允许使用列标签代替列名 -->  
    19.         <setting name="useColumnLabel" value="true" />  
    20.                 <!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->  
    21.         <setting name="useGeneratedKeys" value="true" />  
    22.                 <!-- 给予被嵌套的resultMap以字段-属性的映射支持 -->  
    23.         <setting name="autoMappingBehavior" value="FULL" />  
    24.                 <!-- 对于批量更新操作缓存SQL以提高性能  -->  
    25.         <setting name="defaultExecutorType" value="BATCH" />  
    26.                 <!-- 数据库超过25000秒仍未响应则超时 -->  
    27.         <setting name="defaultStatementTimeout" value="25000" />  
    28.     </settings>  
    29.    
    30. <!--
    31. 第一种写法
    32. 类型别名是为Java类型命名一个短的名字。它只和XML配置有关,只用来减少类完全限定名的多余部分
    33.   <typeAliases>
    34.   <typeAlias alias="Person" type="com.msun.daomain.Person"/>
    35. </typeAliases>
    36. -->
    37. <!-- 第二种写法  配合注解使用,在该包com.msun.daomain下使用注解@Alias("person")
    38. 指定一个包中所有类的别名-->
    39. <typeAliases>
    40.   <package name="com.msun.daomain"/>
    41. </typeAliases>
    42. <!--
    43. development:开发模式
    44. work:工作模式
    45. -->
    46.   <environments default="development" >
    47.     <environment id="development" >
    48.       <transactionManager type="JDBC" />
    49.       
    50.       <!-- JDBC连接对象的数据源连接池的实现,用来避免创建新的连接实例时必要的初始
    51.       连接和认证时间。这是一种当前Web应用程序用来快速响应请求很流行的方法。 -->
    52.       <dataSource type="POOLED" >
    53.         <property name="driver" value="${driver}"/>
    54.         <property name="url" value="${url}"/>
    55.         <property name="username" value="${username}"/>
    56.         <property name="password" value="${password}"/>
    57.       </dataSource>
    58.     </environment>
    59.   </environments>
    60. </configuration>
    复制代码

           以上是对MyBatis的属性进行配置及设置JDBC连接对象的数据源连接池的实现。

    1. @Override
    2. public void insertUser(JSONObject user) {
    3. SqlSession session = null;
    4. try {
    5. //根据 JDBC 规范建立与数据库的连接;
    6. session = sqlSessionFactory.openSession();
    7. //通过反射打通 Java 对象与数据库参数交互之间相互转化关系
    8. UserMapper mapper = session.getMapper(UserMapper.class);
    9. mapper.insertUser(parasJson(user));
    10. session.commit();
    11. } finally {
    12. session.close();
    13. }
    14. }
    复制代码

          以上代码完成数据写入数据库的操作。
      其向外提供生成代理对象的函数getMapper()方法如下:

    1. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    2.     //如果不存在这个mapper,则直接抛出异常
    3.     if (!knownMappers.contains(type))
    4.       throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    5.     try {
    6.       //返回代理类
    7.       return MapperProxy.newMapperProxy(type, sqlSession);
    8.     } catch (Exception e) {
    9.       throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    10.     }
    11.   }
    复制代码

          MyBatis中涉及到ORM的思想,ORM框架最重要功能是将面向对象方法中的对象和关系型数据库中的表关联了起来,在关联过程中就必然涉及到对象中的数据类型(java数据类型)和数据库中的表字段类型的转换,Mybatis中的org.apache.ibatis.type包主要就是实现这个功能。​只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。当前ORM框架主要有三种:Hibernate,iBATIS,EclipseLink。
          映射关系体现在mapper文件中,有两种方式进行关联,分别是:基于注解的方式和编写映射文件(xml)的形式。基于注解的形式如下:

    1. public interface UserMapper {
    2. @Select(value="select * from user where id = #{id}")
    3. public User findUserById(int id);
    4. @Select(value="select * from user where username = #{username} and password = #{password}")
    5. public User login(User user);
    6. @Insert(value="insert into user (id,username,phone,email,password) values(#{id},#{username},#{phone},#{email},#{password})")
    7. public void insertUser(User user);
    8. @Select(value="select * from user where nickname = #{nickname} and email = #{email}")
    9. public User findUserByNameAndEmail(User user);
    10. }
    复制代码

          以插入操作为例,插入的数据为#{id}...其属性为domain域中类的相关属性。框架会在属性中进行相应属性的查找。若查找不到则会报错。

    1. public class SqlSessionUtils {
    2. /**
    3. * SqlSessionFactory对象可以看成DataSource(数据库连接池)
    4. * 在应用执行期间,应该只创建一次,建议使用单例模式  
    5. */
    6. private static SqlSessionFactory factory=null;
    7. public static SqlSessionFactory getSessionFactory(){
    8. if(factory==null){
    9. synchronized (SqlSessionUtils.class) {
    10. if(factory==null){
    11. try {
    12. //1.创建配置文件的输入流
    13. String resource = "mybatis.xml";
    14. InputStream inputStream = Resources.getResourceAsStream(resource);
    15. //2.创建SqlSessionFactory
    16. factory=new SqlSessionFactoryBuilder().build(inputStream);
    17. //添加映射器类(注解方式),避免了对xml文件的依赖
    18. factory.getConfiguration().addMapper(MyLotteryMapper.class);
    19. factory.getConfiguration().addMapper(LotteryMapper.class);
    20. factory.getConfiguration().addMapper(UserMapper.class);
    21. } catch (IOException e) {
    22. throw new RuntimeException(e);
    23. }
    24. }
    25. }
    26. }
    27. return factory;
    28. }
    29. }
    复制代码


          在使用ibatis执行数据库访问时,会调用形如

    1.         getSqlMapClientTemplate().queryForObject("getCityByCityId", cityId);
    复制代码

          这样的代码。这样的形式要求调用方选择需要使用的函数(queryForObject、queryForList、update),还需要告诉这个函数具体执行哪一个statement(上文中是“getCityByCityId”),在这个过程中如果有一个地方选择错误或者拼写错误,不仅没有办法达到自己的期望值,可能还会出现异常,并且这种错误只有在运行时才能够发现。
          mybatis对此进行了改进,只要先声明一个接口,就可以利用IDE的自动完成功能帮助选择对应的函数,简化开发的同时增加了代码的安全性。(如以下接口UserMapper所示 )
    1. [/code]
    2. [code]        public interface UserMapper {
    3.         @Select(value="select * from user where id = #{id}")
    4.         public User findUserById(int id);
    5.        
    6.         @Select(value="select * from user where username = #{username} and password = #{password}")
    7.         public User login(User user);
    8.        
    9.         @Insert(value="insert into user (id,username,phone,email,password) values(#{id},#{username},#{phone},#{email},#{password})")
    10.         public void insertUser(User user);
    11.         @Select(value="select * from user where nickname = #{nickname} and email = #{email}")
    12.         public User findUserByNameAndEmail(User user);
    13.         }
    复制代码

          以下为MapperRegistry中addMapper方法的底层代码:

    1. [/code]
    2. [code]public void addMapper(Class<?> type) {
    3.     //因为Java的动态代理只能实现接口,因而在注册mapper时也只能注册接口
    4.     if (type.isInterface()) {
    5.       //如果已经注册过了,则抛出异常,而不是覆盖
    6.       if (knownMappers.contains(type)) {
    7.         throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
    8.       }
    9.       boolean loadCompleted = false;
    10.       try {
    11.         //先将这个mapper添加到mybatis中,如果加载过程中出现异常需要再将这个mapper从mybatis中删除
    12.         knownMappers.add(type);
    13.         // It"s important that the type is added before the parser is run
    14.         // otherwise the binding may automatically be attempted by the
    15.         // mapper parser.  If the type is already known, it won"t try.
    16.         
    17.         //下面两行代码其实做了很多的事,由于涉及的东西较多,在此不做过多的描述,留待以后专门进行介绍
    18.         MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
    19.         parser.parse();
    20.         loadCompleted = true;
    21.       } finally {
    22.         if (!loadCompleted) {
    23.           knownMappers.remove(type);
    24.         }
    25.       }
    26.     }
    27.   }
    复制代码

      




           另外,MyBatis持久层框架还涉及到动态绑定、反射、单例、工厂设计模式。个人感觉,应深入到底层代码去阅读,只有这样才可以对框架有进一步的了解。
    参考网址
    [url=>http://www.th7.cn/Program/java/201407/240933.sHTML

    [url=>http://blog.csdn.net/hupanfeng/article/details/9238127  
    mybatis源代码分析之binding包
    [url=>http://www.cnblogs.com/sunzhenchao/arcHive/2013/05/13/3075854.html http://www.cnblogs.com/sunzhenchao/archive/2013/05/13/3075854.html[/url]

    Mybatis源代码分析之别名
    http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3010527.html

    动态代理 反射机制
    java动态代理(JDK和cglib)
    http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
    http://www.cnblogs.com/sunzhenchao/tag/Mybatis/

    Mybatis源代码分析之类型转换
    http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3009431.html

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-26 19:01 , Processed in 0.399522 second(s), 52 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表