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标签中的配置优先级最低 ‐‐>
11
32 <typeAliases>
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"));
12
16
Batis 允许使用插件来拦截的方法调用包括: nsaction, close, isClosed)
24 25 //Mybatis创建对象是会使用objectFactory来创建对象,一般情况下不会自己配置 这个objectFactory,使用系统默认的objectFactory就好了
29
32 需要指定环境id,如果不指定的话,会选择默认的环境;
36
39 40 //无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还 从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类 | y |
型。解析typeHandler。
-
41 typeHandlerElement(root.evalNode("typeHandlers"));
-
42 //解析Mapper
-
43 mapperElement(root.evalNode("mappers"));
-
44 } catch (Exception e) {
-
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对象;