MyBatis解析全局配置文件

 

MyBatis介绍

MyBatis介绍 MyBatis是一个持久层的ORM框架,使用简单,学习成本较低。可以执行自己手 写的SQL语句,比较灵活。但是MyBatis的自动化程度不高,移植性也不高,有 时从一个数据库迁移到另外一个数据库的时候需要自己修改配置,所以称只为半 自动ORM框架

传统JDBC和Mybatis相比的弊病

传统JDBC

@Test
public void test() throws SQLException {

Connection conn=null;
PreparedStatement pstmt=null;
try{
  // 1.加载驱动
  Class.forName("com.mysql.jdbc.Driver");

 // 2.创建连接
  conn= DriverManager.
 getConnection("jdbc:mysql://localhost:3306/mybatis_example", "root"
"123456");

 // SQL语句
  String sql="select id,user_name,create_time from t_user where id=?"
 
  // 获得sql执行者
  pstmt=conn.prepareStatement(sql);
  pstmt.setInt(1,1);
 
  // 执行查询
  //ResultSet rs= pstmt.executeQuery();
  pstmt.execute();
  ResultSet rs= pstmt.getResultSet();
 
  rs.next();
  User user =new User();
  user.setId(rs.getLong("id"));
  user.setUserName(rs.getString("user_name"));
  user.setCreateTime(rs.getDate("create_time"));
  System.out.println(user.toString());

  } catch (Exception e) {
     e.printStackTrace();
  }
  finally{
  // 关闭资源
  try{
   if(conn!=null){
     conn.close();
   }
  if(pstmt!=null){
      pstmt.close();
  }
  } catch (SQLException e) {
  e.printStackTrace();
  }
  }
  }

传统JDBC的问题如下

1.数据库连接创建,释放频繁造成西戎资源的浪费,从而影响系统性能,使 用数据库连接池可以解决问题。

2.sql语句在代码中硬编码,造成代码的不已维护,实际应用中sql的变化可 能较大,sql代码和java代码没有分离开来维护不方便。

3.使用preparedStatement向有占位符传递参数存在硬编码问题因为sql中 的where子句的条件不确定,同样是修改不方便/

4.对结果集中解析存在硬编码问题,sql的变化导致解析代码的变化,系统维 护不方便。

mybatis对传统的JDBC的解决方案

1、数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果 使用数据库连接池可解决此问题。

解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链 接。

2、Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大, sql变动需要改变java代码。

  解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可 能少,占位符需要和参数一一对应。

 解决:Mybatis自动将java对象映射至sql语句,通过statement中的 parameterType定义输入参数的类型。

4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的 resultType定义输出结果的类型。

Mybaits整体体系图

 一个Mybatis最简单的使用例子如下

public class App {
 public static void main(String[] args) {
 String resource = "mybatis‐config.xml";
 Reader reader;
    
try{
//将XML配置文件构建为Configuration配置类
    reader = Resources.getResourceAsReader(resource);
// 通过加载配置文件流构建一个SqlSessionFactory DefaultSqlSessionFactor

    SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(
eader);
   // 数据源 执行器 DefaultSqlSession

    SqlSession session = sqlMapper.openSession();

   try{

   // 执行查询 底层执行jdbc

   //User user = (User)session.selectOne("com.tuling.mapper.selectById", 1);

   UserMapper mapper = session.getMapper(UserMapper.class);

   System.out.println(mapper.getClass());

   User user = mapper.selectById(1L);

   System.out.println(user.getUserName());

   } catch (Exception e) {
       e.printStackTrace();
   }finally {
       session.close();
   }

   } catch (IOException e) {
       e.printStackTrace();
   }

   }

   }
总结下就是分为下面四个步骤
从配置文件(通常是XML文件)得到SessionFactory;
 从SessionFactory得到SqlSession;
 通过SqlSession进行CRUD和事务的操作; 
  执行完相关操作之后关闭Session。

MyBatis 源码编译


MyBatis的源码编译比较简单, 随便在网上找一篇博客即可,在这里不多说 https://www.cnblogs.com/mokingone/p/9108999.html

如果希望在spring源码中引入你自己的这份源码,可以做如下操作

1. 修改你mybatis源码的pom的<version> 这样可以和官方的区分开来

    <version>3.5.3‐xsls</version>
2. 这样你在spring源码中就可以引入这份mybatis源码了.

          a. 如果引入mybatis-spring 同样需要做1、3步骤

            compile("org.mybatis:mybatis‐spring:2.0.3‐xsls")

            compile("org.mybatis:mybatis:3.5.3‐xsls")

3. 当然,如果你想在spring这边看到你mybatis源码相关的注释,还得在mybatis源码的 pom里面加入plugin,使它生成 jar 的同时 生成 sources 包

  • 1 <plugin>
  • 2 <artifactId>maven‐source‐plugin</artifactId>
  • 3 <version>3.0.1</version>
  • 4 <configuration>
  • 5 <attach>true</attach>
  • 6 </configuration>
  • 7 <executions>
  • 8 <execution>
  • 9 <phase>compile</phase>
  • 10 <goals>
  • 11 <goal>jar</goal>
  • 12 </goals>
  • 13 </execution>
  • 14 </executions>
  • 15 </plugin>

启动流程分析

 String resource = "mybatis‐config.xml";

 //将XML配置文件构建为Configuration配置类
reader = Resources.getResourceAsReader(resource);
// 通过加载配置文件流构建一个SqlSessionFactory DefaultSqlSessionFactory

 SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);

通过上面代码发现,创建SqlSessionFactory的代码在 SqlSessionFactoryBuilder中,进去一探究竟:

1 //整个过程就是将配置文件解析成Configration对象,然后创建SqlSessionFactory 的过程

2 //Configuration是SqlSessionFactory的一个内部属性
3 public SqlSessionFactory build(InputStream inputStream, String enviroment, Properties properties) {

4 try{

5 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environm nt, properties);

6  return build(parser.parse());

7  } catch (Exception e) {

8  throw ExceptionFactory.wrapException("Error building SqlSession.",e);

} finally {
ErrorContext.instance().reset();
try{
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error. }
}
}

 public SqlSessionFactory build(Configuration config) {
         return new DefaultSqlSessionFactory(config);
 }
下面我们看下解析配置文件过程中的一些细节。

先给出一个配置文件的列子: 

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 <!‐‐SqlSessionFactoryBuilder中配置的配置文件的优先级最高;config.proper ties配置文件的优先级次之;properties标签中的配置优先级最低 ‐‐>

  1. 7  <properties resource="org/mybatis/example/config.properties">

  2. 8  <property name="username" value="dev_user"/>

  3. 9  <property name="password" value="F2Fa3!33TYyg"/>

  4. 10  </properties>

11

  1. 12  <!‐‐一些重要的全局配置‐‐>

  2. 13  <settings>

  3. 14  <setting name="cacheEnabled" value="true"/>

  4. 15  <!‐‐<setting name="lazyLoadingEnabled" value="true"/>‐‐>

  5. 16  <!‐‐<setting name="multipleResultSetsEnabled" value="true"/>‐‐>

  6. 17  <!‐‐<setting name="useColumnLabel" value="true"/>‐‐>

  7. 18  <!‐‐<setting name="useGeneratedKeys" value="false"/>‐‐>

  8. 19  <!‐‐<setting name="autoMappingBehavior" value="PARTIAL"/>‐‐>

  9. 20  <!‐‐<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>‐‐>

  10. 21  <!‐‐<setting name="defaultExecutorType" value="SIMPLE"/>‐‐>

  11. 22  <!‐‐<setting name="defaultStatementTimeout" value="25"/>‐‐>

  12. 23  <!‐‐<setting name="defaultFetchSize" value="100"/>‐‐>

  13. 24  <!‐‐<setting name="safeRowBoundsEnabled" value="false"/>‐‐>

  14. 25  <!‐‐<setting name="mapUnderscoreToCamelCase" value="false"/>‐‐>

  15. 26  <!‐‐<setting name="localCacheScope" value="STATEMENT"/>‐‐>

  16. 27  <!‐‐<setting name="jdbcTypeForNull" value="OTHER"/>‐‐>

  17. 28  <!‐‐<setting name="lazyLoadTriggerMethods" value="equals,clone,hashcode,toString"/>‐‐>

  18. 29  <!‐‐<setting name="logImpl" value="STDOUT_LOGGING" />‐‐>

  19. 30  </settings>

32 <typeAliases> 
34 </typeAliases> 

  1. 36  <plugins>

  2. 37  <plugin interceptor="com.github.pagehelper.PageInterceptor">

  3. 38  <!‐‐默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBou

nds.limit = 0 就会查询出全部的结果‐‐>

39  <!‐‐如果某些查询数据量非常大,不应该允许查出所有数据‐‐>

40  <property name="pageSizeZero" value="true"/>

41  </plugin>

42  </plugins>

43

44  <environments default="development">

45  <environment id="development">

46  <transactionManager type="JDBC"/>

47  <dataSource type="POOLED">

48  <property name="driver" value="com.mysql.jdbc.Driver"/>

49  <property name="url" value="jdbc:mysql://10.59.97.10:3308/windty"/>

50  <property name="username" value="windty_opr"/>

51  <property name="password" value="windty!234"/>

52  </dataSource>

53  </environment>

54  </environments>

55

56  <databaseIdProvider type="DB_VENDOR">

57  <property name="MySQL" value="mysql" />

58  <property name="Oracle" value="oracle" />

59  </databaseIdProvider>

60

61  <mappers>

62  <!‐‐这边可以使用package和resource两种方式加载mapper‐‐>

63  <!‐‐<package name="包名"/>‐‐>

64  <!‐‐<mapper resource="./mappers/SysUserMapper.xml"/>‐‐>

65  <mapper resource="./mappers/CbondissuerMapper.xml"/>

66  </mappers>
68 </configuration>

下面是解析配置文件的核心方法:

private void parseConfiguration(XNode root) {

try{
//issue #117 read properties first //解析properties标签,并set到Configration对象中

//在properties配置属性后,在Mybatis的配置文件中就可以使用${key}的形式

6 propertiesElement(root.evalNode("properties")); 7

8 //解析setting标签的配置 9 Properties settings =

settingsAsProperties(root.evalNode("settings"));
  1. 10  //添加vfs的自定义实现,这个功能不怎么用

  2. 11  loadCustomVfs(settings);

12

  1. 13  //配置类的别名,配置后就可以用别名来替代全限定名

  2. 14  //mybatis默认设置了很多别名,参考附录部分

  3. 15  typeAliasesElement(root.evalNode("typeAliases"));

16

  1. 17  //解析拦截器和拦截器的属性,set到Configration的interceptorChain中

  2. 18  //MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,M

Batis 允许使用插件来拦截的方法调用包括:
19 //Executor (update, query, flushStatements, commit, rollback, getTr

nsaction, close, isClosed)
  1. 20  //ParameterHandler (getParameterObject, setParameters)

  2. 21  //ResultSetHandler (handleResultSets, handleOutputParameters)

  3. 22  //StatementHandler (prepare, parameterize, batch, update, query)

  4. 23  pluginElement(root.evalNode("plugins"));

24

25 //Mybatis创建对象是会使用objectFactory来创建对象,一般情况下不会自己配置 这个objectFactory,使用系统默认的objectFactory就好了

  1. 26  objectFactoryElement(root.evalNode("objectFactory"));

  2. 27  objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));

  3. 28  reflectorFactoryElement(root.evalNode("reflectorFactory"));

29

  1. 30  //设置在setting标签中配置的配置

  2. 31  settingsElement(settings);

32
33 //解析环境信息,包括事物管理器和数据源,SqlSessionFactoryBuilder在解析时

需要指定环境id,如果不指定的话,会选择默认的环境;

  1. 34  //最后将这些信息set到Configration的Environment属性里面

  2. 35  environmentsElement(root.evalNode("environments"));

36

  1. 37  //

  2. 38  databaseIdProviderElement(root.evalNode("databaseIdProvider"));

39

40 //无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还 从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类

y

型。解析typeHandler。

  1. 41  typeHandlerElement(root.evalNode("typeHandlers"));

  2. 42  //解析Mapper

  3. 43  mapperElement(root.evalNode("mappers"));

  4. 44  } catch (Exception e) {

  5. 45  throw new BuilderException("Error parsing SQL Mapper Configuration.

Cause: " + e, e);

46 }

47 }

 

上面解析流程结束后会生成一个Configration对象,包含所有配置信息,然后会

创建一个SqlSessionFactory对象,这个对象包含了Configration对象。 简单总结

对于MyBatis启动的流程(获取SqlSession的过程)这边简单总结下: SqlSessionFactoryBuilder解析配置文件,包括属性配置、别名配置、

拦截器配置、环境(数据源和事务管理器)、Mapper配置等;解析完这些 配置后会生成一个Configration对象,这个对象中包含了MyBatis需要的所有配置,然后会用这个Configration对象创建一个SqlSessionFactory对 象,这个对象中包含了Configration对象;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值