Mybatis源码解析1—— JDBC
在之前的文章中,我为大家介绍了 Mybatis 的详细用法,算是基础教程。
详细链接:Mybatis 基础教程
言归正传,只懂基础可不行,接下来将给大家带来高阶的源码解析教程,从浅入深,通过源码解析,图例结合,抽丝剥茧,让大家看的不吃力,并且能够深刻理解 Mybatis 这个框架的底层实现原理,让大家学到的不仅仅是这个框架用法,而是通过这个框架理解其设计思想。
1、JDBC
我相信所有开发者第一次与数据库打交道时,就是通过 JDBC 来实现的,第一次通过程序获取到数据库中的数据时,那种高兴,那种吃惊,反正我依稀历历在目。
什么是 JDBC:JDBC 是Java与数据库交互的API,用来规范客户端程序如何来访问数据库的应用程序接口。
通常分为两组API:
①、面向Java应用程序开发人员的API,是一个标准的API,且不同数据库具有不同的实现。
②、面向数据库驱动开发人员,是前者的底层支持。
因为大家都是Java开发人员,这里我们就介绍第一组API。
JDBC API主要位于JDK中的java.sql包中(之后扩展的内容位于javax.sql包中)
下面介绍几个关键的接口,注意这都是JDK内部提供的一些接口,具体实现得看具体的数据库驱动,比如MySQL,我们通常会在maven或gradle配置mysql-connectior-java ,下面接口的具体实现就在其中。
①、Driver:驱动程序,会将自身加载到DriverManager中去.
②、DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。
③、Connection:数据库连接,负责与进行数据库间通讯,SQL执行以及事务处理都是在某个特定Connection环境中进行的。可以产生用以执行SQL的Statement。
④、Statement:用来执行SQL查询和更新(针对静态SQL语句和单次执行)。
⑤、PreparedStatement:用来执行包含动态参数的SQL查询和更新(预编译,在服务器端编译,允许重复执行以提高效率)。
⑥、CallableStatement:用来调用数据库中的存储过程。
⑦、ResultSet:用来存储数据库查询操作返回的结果。
⑧、SQLException:表示在数据库连接的建立、SQL语句的执行、关闭等过程中发生了异常。
2、完整的交互过程
下面,我们通过JDBC来完成一次数据库查询操作,步骤如下:
①、加载数据库驱动
②、获取数据库连接(通过数据库URL,用户名,密码)
③、定义SQL语句
④、通过数据库连接,创建 Statement 对象或者 PreparedStatement 对象
⑤、通过 Statement 对象执行 SQL 语句,得到结果集 ResultSet 对象
⑥、读取 ResultSet 对象,转换成我们要的 JavaBean
⑦、关闭数据库连接、Statement、ResultSet等对象,释放相关资源
代码实现如下:
package com.itcoke.bean; public class Person { private Long pid; private String pname; private Integer page; public Long getPid() {
return pid;
} public void setPid(Long pid) {
this.pid = pid;
} public String getPname() {
return pname;
} public void setPname(String pname) {
this.pname = pname;
} public Integer getPage() {
return page;
} public void setPage(Integer page) {
this.page = page;
} @Override
public String toString() {
return "Person{" +
"pid=" + pid +
", pname='" + pname + '\'' +
", page=" + page +
'}';
}
}
package com.itcoke.jdbc; import com.itcoke.bean.Person; import java.sql.*;
import java.util.ArrayList;
import java.util.List; public class JDBCUtils {
//MySQL数据库驱动,注意多了一个cj,com.mysql.jdbc.Driver和mysql-connector-java 5一起用
public static String driverClass = "com.mysql.cj.jdbc.Driver";
//MySQL用户名
public static String userName = "root";
//MySQL密码
public static String passWord = "root1234";
//MySQL URL
public static String url = "jdbc:mysql://localhost:3306/mybatis-study";
//定义数据库连接
public static Connection conn = null;
//定义声明数据库语句,使用 预编译声明 PreparedStatement提高数据库执行性能
public static PreparedStatement ps = null;
//定义返回结果集
public static ResultSet rs = null; public static List<Person> selectPersonByName(String pname){
List<Person> personList = new ArrayList<>(); try {
// 1、加载数据库驱动
Class.forName(driverClass);
// 2、获取数据库连接
conn = DriverManager.getConnection(url,userName,passWord);
// 3、定义 sql 语句,?表示占位符
String sql = "select * from person where pname=?";
// 4、获取预编译处理的statement
ps = conn.prepareStatement(sql);
//设置sql语句中的参数,第一个为sql语句中的参数的?(从1开始),第二个为设置的参数值
ps.setString(1, "itcoke");
// 5、向数据库发出 sql 语句查询,并返回结果集
rs = ps.executeQuery();
while(rs.next()){
// 6、读取ResultSet,转换成我们要的对象
Person person = new Person();
person.setPid(rs.getLong("pid"));
person.setPname(rs.getString("pname"));
personList.add(person);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
// 7、关闭数据库连接
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return personList;
} public static void main(String[] args){
List<Person> personList = JDBCUtils.selectPersonByName("itcoke");
System.out.println(personList);
}
}
PS:数据库名称为 mybatis-study,表为 person
3、缺点分析
①、问题一:每执行一次增删改查,就要建立连接,关闭连接,频繁的获取连接和关闭连接,会造成数据库资源浪费,影响数据库性能。
设想解决:使用数据库连接池管理数据库连接
②、问题二:将 sql 语句硬编码到程序中,如果sql语句修改了,那么需要重新编译 Java 代码,不利于系统维护
设想解决:将 sql 语句可配置化,比如设置到 xml 文件中,这样即使 sql 语句变化了,我们也不需要对 Java 代码进行修改
③、问题三:在 PreparedStatement 中设置参数,对占位符设置值都是硬编码在Java代码中,不利于系统维护
设想解决:将 sql 语句以及占位符和参数都配置到 xml 文件中
④、问题四:从 resultset 中遍历结果集时,对表的字段存在硬编码,不利于系统维护
设想解决:将查询的结果集自动映射为 Java 对象
⑤、问题五:重复性代码特别多,包括建立建立,加载驱动等
设想解决:抽取封装公共代码
⑥、问题六:没有缓存,如果存在数据量大,且频繁查询的情况,这种方式性能特别低
设想解决:集成缓存框架去操作数据库
⑦、问题七:sql 的移植性不好,如果换个数据库,那么sql 语句可能要重写
设想解决:在 JDBC 和 数据库之间插入第三方框架,用第三方去生成 sql 语句,屏蔽数据库的差异
4、ORM框架
为了解决上面这些缺点,ORM(Object Relational Mapping,对象-关系映射)框架应运而生。
ORM 模型就是数据库的表和Java对象的映射关系模型,它主要解决数据库数据和Java对象的相互映射,通过映射关系,我们可以简单而迅速的把数据库数据转换成Java对象,从而让开发人员无需对数据库相关知识深入了解,便可以操作数据库数据。
当前市面上比较主流的ORM框架包括 Hibernate、Mybatis、Spring JDBC 等等,各有优缺点,这里可乐不做详细介绍,本系列文章主要是介绍当前使用最广泛的 ORM框架——Mybatis。
其更轻量、更可控的特性,比较适合当前主流业务,特别是大数据量、高并发的场景。
5、小结
本文我们介绍了JDBC直接操作数据库的一些问题,引申出解决此类问题的ORM框架,其中 Mybatis 是其中的佼佼者,
那么为什么 Mybatis 能够解决 JDBC 直接操作数据库的痛点?它又是如何实现的呢?
不要走开,我们下篇文章更精彩!
Mybatis源码解析1—— JDBC的更多相关文章
- 【Mybatis源码解析】- JDBC连接数据库的原理和操作
JDBC连接数据库的原理和操作 JDBC即Java DataBase Connectivity,java数据库连接:JDBC 提供的API可以让JAVA通过API方式访问关系型数据库,执行SQL语句, ...
- mybatis源码-解析配置文件(三)之配置文件Configuration解析
目录 1. 简介 1.1 系列内容 1.2 适合对象 1.3 本文内容 2. 配置文件 2.1 mysql.properties 2.2 mybatis-config.xml 3. Configura ...
- Mybatis源码解析,一步一步从浅入深(一):创建准备工程
Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...
- Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)
在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到 代码:XMLConfigBuilder parser = new XMLConfigBuilder(read ...
- Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例
在Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们看到了XMLConfigBuilder(xml配置解析器)的实例化.而且这个实例化过程在文章:Mybatis源码解析,一步一步从浅 ...
- Mybatis源码解析,一步一步从浅入深(七):执行查询
一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...
- Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?
Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? 如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...
- Mybatis源码解析(二) —— 加载 Configuration
Mybatis源码解析(二) -- 加载 Configuration 正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...
- Mybatis源码解析3——核心类SqlSessionFactory,看完我悟了
这是昨晚的武汉,晚上九点钟拍的,疫情又一次来袭,曾经熙熙攘攘的夜市也变得冷冷清清,但比前几周要好很多了.希望大家都能保护好自己,保护好身边的人,生活不可能像你想象的那么好,但也不会像你想象的那么糟. ...
随机推荐
- Mysql的5种索引添加类型
1.添加普通索引: alter table 'table_name' add index index_name('column') 2.添加主键索引 alter table 'table_name' ...
- 【原创】SystemVerilog中的多态和虚方法
封装可以隐藏实现细节,使代码模块化,继承可以扩展已经存在的代码模块,目的都是为了代码重用.多态是为了实现接口的重用.在SystemVerilog中,子类和父类之间多个子程序使用同一个名字的现象称为Sy ...
- golang变量与常量
变量 变量 在程序运行中可以改变的量 枚举 var ( a3 = 1 a4 = 2 ) golang不同类型变量不能替换 func main() { var a int = 10 a = 20 a = ...
- 5、修改oracle的字符集
注意:修改字符集前需要将表空间进行数据泵备份: 5.1.修改server端字符集: 1.登录到oracle实例查看字符集: [oracle@slave-node2 ~]$ echo $ORACLE_S ...
- CRM系统什么时候需要使用
CRM客户关系管理系统,相信每个人都会有所了解.现如今随着企业的发展需求,CRM软件已经成为了企业管理的刚需.无论是何种行业和规模的企业,客户都是最重要的资源,提高客户满意度也是企业的首要任务.如果您 ...
- Java的反射机制一
Java具有一定的动态性,我们可以利用反射机制,字节码操作来获得类似动态语言的特性. 动态操作对象,构造方法,属性,方法 Demo2 如何取得属性和方法以及构造器 public class Demo2 ...
- bugku Crypto 下半部分wp
1. 百度托马斯这个人居然还发明了一种轮转的加密法,发现原理是,他将很多行乱序的26个字母,插到一根柱子上,参考糖葫芦的样子,可以旋转每一行,设置自己要发送的明文后,向对方发送乱码的一列,对方只要将这 ...
- 使用 Java 和 Maven (JBake) 生成静态网站
使用 JBake("mvn generate-resources")构建您的静态网站或博客.使用布局.宏和数据文件. 我们迁移了整个www.optaplanner.org网站(13 ...
- 「AGC034D」 Manhattan Max Matching
「AGC034D」 Manhattan Max Matching 传送门 不知道这个结论啊... (其实就是菜嘛) 首先 \(O(n^2)\) 的建边显然不太行. 曼哈顿距离有这样一个性质,如果将绝对 ...
- Java基础00-运算符4
1. 算术运算符 1.1 运算符和表达式 1.2 算数运算符 余数的计算取余数是指整数除法中被除数未被除尽部分,且余数的取值范围为0到除数之间(不包括除数)的整数 ,例如27除以6,商数为4,余数为3 ...