1. 从JDBC说起
1.1 JDBC的问题
JDBC
,Java
语言中用来访问数据库的应用程序接口。废话不多说,先看一个JDBC的程序。
jdbc.properties
driver=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://192.168.100.120:3306/Antennapara?autoReconnect=true
user=monica
password=***
JDBCUtils.java
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtils {
public static Connection getConnection() throws Exception {
Properties properties = new Properties();
InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream(
"jdbc.properties");
properties.load(in);
String driver = properties.getProperty("driver");
String jdbcUrl = properties.getProperty("jdbcUrl");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
Class.forName(driver);
Connection connection = DriverManager.getConnection(jdbcUrl, user,
password);
return connection;
}
public static void release(Statement statement, Connection connection,
ResultSet resultset) {
if (resultset != null) {
try {
resultset.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
JDBCConnection.java
mport java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCConnection {
private Connection conn;
private Statement statement;
//or private PreparedStatement preparedStatement;
private ResultSet rs;
public JDBCConnection(){
try {
conn=JDBCUtils.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
public void getResultSet(String para) {
String sql="select * from Antennapara where Param="+"'"+para+"'"; //[2]
try {
statement = conn.createStatement();
rs=statement.executeQuery(sql);
/*** or use PreparedStatement*****
String sql="select * from Antennapara where Param=?";
preparedStatement = conn.preparestatement(sql);
preparedStatement .setstring(1, para); //[3]
rs = preparedStatement .executequery();
*/
while(rs.next()){
String recv=rs.getString("Param"); //[4]
System.out.println(recv);
for (int i = 1; i < 23; i++) {
double p=rs.getDouble("P"+i); //[4]
System.out.println(p);
};
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.release(statement, conn, rs); //[1]
}
}
public void update(String sql) {
try {
conn = JDBCUtils.getConnection();
statement = conn.createStatement();
statement.execute(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(statement, conn, rs); //[1]
}
}
public static void main(String[] args) {
new JDBCConnection().getResultSet("Q_TMP");
}
}
看完上面的程序,结合一些资料,我们先来说一下JDBC
的问题都有哪些。
- 在连接数据库的过程中,使用时创建连接,不使用便立即释放连接,对数据库连接的开启和关闭操作频繁,造成数据库资源的浪费,影响数据库乃至整个应用的性能(见上方代码中注释
[1]
); - 将
sql
语句硬编码到代码中,不利于系统的维护,修改将违反“开闭原则”(见上方代码中注释[2]
); - 想
PreparedStatement
中设置参数时,将占位符号位置和设置的参数值硬编码到代码中,不利于系统的维护(见上方代码中注释[3]
); - 从
ResultSet
中遍历结果集数据时,将需要获取的字段进行了硬编码,不利于系统的维护(见上方代码中注释[4]
)。
1.2 设想的解决方法
针对上面提出的问题,设想的解决方法如下(与上述问题一 一对应):
-
使用数据库连接池管理数据库的连接;
下图即为从直接与数据库连接到使用数据库连接池连接之间的转换过程。使用连接池连接时,连接池与数据库之间存在若干个长连接(数量可配置),客户端与连接池交互,通过连接池获取连接;客户端用完后,连接被释放,供下一个请求使用。因为连接池与数据库之间的连接是长连接,连接初始化完成后就一直存在,不存在频繁的开启与关闭;客户端也不直接与数据库交互。这样就可以提升数据库以及应用整体的性能。
-
将
sql
语句配置到配置文件中。即使当sql语句需要变化,也不需要重新编译原有代码; -
将占位符号和设置的参数全部配置在配置文件中;
-
将返回的结果集自动映射成对象,这样就可以操作对象而不需要单个字段单独获取。
以上提到的这些,恰好MyBatis
都可以做到。下面来看一看MyBatis
是何方神圣吧!
2. 初识MyBatis
2.1 MyBatis是什么
Mybatis
,曾经叫IBatis
,Apache
开源项目,曾经托管在Google Code
下,后来托管到GitHub
(https://github.com/mybatis/mybatis-3),是一个优秀的持久层1框架。
MyBatis
让开发者们专注于sql
本身,通过其提供的映射方法,自由灵活的生成满足需求的sql
语句,可将向PreparedStatement
中传入的参数自动进行输入映射,将查询到的结果集灵活映射成Java对象(输出映射)。
2.2 框架图
有了上面的图,在用文字说明一下吧。
- 配置文件
SqlMapConfig.xml
:是MyBatis
的全局配置文件,用于配置数据库、事务等MyBatis
的运行环境,名称可以不必是这个,这个文件是需要在代码里面去读取的,不管叫什么名字,只需要对应起来即可。(在后续和Spring
整合之后,有些配置都转移到Spring
的配置里面去了,如果里面没什么其他的配置的话,甚至基本可以不用)mapper.xml
,sql
映射文件,用于配置操作数据库的sql语句。此文件需要在SqlMapConfig.xml
中加载。需要有Mapper.java
与其对应,不必非叫这个名字,但最好叫xxxMapper
,xml
与java
名字相同且在同一目录下。
-
通过加载核心配置文件的流构造出
SqlSessionFactory
(会话工厂)。由会话工厂创建会话(SqlSession
)用以操作数据库。 -
SqlSession
(会话)由SqlSessionFactory
创建,用以操作数据库。 -
Executor
是MyBatis
封装的在SqlSession
内部的一个接口,用以操作数据库。Executor
接口有两个实现,基本执行器和缓存执行器。 -
Mapped Statement
是MyBatis
底层封装对象,对sql
语句和输入/输出映射等操作数据库的信息进行封装。输入映射,即入参类型,可以是Java基本类型、Map
和POJO(Plain Ordinary Java Object
, 简单Java
对象,普通JavaBeans)
,出参类型和入参类型一致,但出参类型还可以是一个包含上述类型(除Map
外?)的一个List
。
3. 总结
MyBatis是一个持久层框架,可用于代替相对比较笨拙的JDBC,可以配置数据库连接池,通过配置文件配置数据库连接和sql语句,避免硬编码带来的维护问题。
MyBatis框架由配置文件、SqlSessionFactory、SqlSession、Executor、底层封装对象等部分组成,底层封装对象属于输入映射和输出映射之间生成的产物,输入和输出参数基本相同,可以是Java基本类型、Map和POJO,输出参数还可以是一个List。
4. 参考资料
- MyBatis User Guide
- 传智播客 《SpringMVC+MyBatis由浅入深》视频教程
通常意义上将整个应用业务分为三层,及表示层、业务层和持久层。表示层的主要作用是界面展示,接收请求,分发请求;业务层主要完成业务逻辑的整体实现,在
SSM
里面由Spring
负责,较好的粘合表示层和持久层;持久层,在系统逻辑层面上,专注于实现数据持久化的相对独立领域,负责向(或从)一个或多个数据存储器(如数据库)中存储(或者获取)数据。 ↩︎