首先提出一个问题:
在使用常规JDBC进行访问数据库的时候,我们如果需要对sql语句进行修改的时候,我们是否可以不进入每个类去修改相关的SQL的字符串吗?
在传统的JDBC连接数据库的开发模式下,当需要操作数据库的时候,首先我们需要:
- 创建数据库连接类DBConnection
- 通过getConnection方法获取数据库连接对象
- 然后使用数据库连接对象的prepareStatement方法将编写好的SQL语句预编译。
- 传入需要操作的参数,并执行SQL语句
常规JDBC如下所示:
public class JDBConnection {
private final String dbDrive = "com.mysql.cj.jdbc.Driver";
private final String url = "jdbc:mysql://localhost:3306/data?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true";
private final String user = "root"; //数据库账户名
private final String Passwd = "123456"; //数据库密码
private Connection con = null;
public JDBConnection() {
try {
Class.forName(dbDrive).newInstance();
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("数据库加载失败!");
}
//System.out.println("数据库加载成功!");
}
public boolean creatConnection() {
try {
con = DriverManager.getConnection(url, user, Passwd);
con.setAutoCommit(true);
} catch (SQLException e) {
System.out.println(e.toString());
}
return true;
}
public boolean executeUpdate(String sql) { //对数据库进行增加,修改,删除
if (con == null) {
creatConnection();
}
try {
Statement stmt = con.createStatement();
int iCount = stmt.executeUpdate(sql);
//System.out.println("操作成功,所影响的记录数为" + String.valueOf(iCount));
return true;
} catch (SQLException e) {
return false;
}
}
public ResultSet executeQuery(String sql) //对数据库进行查询操作
{
ResultSet rs;
try {
if (con == null) {
creatConnection();
}
Statement stmt = con.createStatement();
rs = stmt.executeQuery(sql);
} catch (Exception e) {
return null;
}
return rs;
}
public void closeConnecstion() {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
我们对JDBC的使用是首先new一个JDBConnection的对象,我们再传入我们需要执行的sql语句。
public class main {
public static void main(String[] args) {
JDBConnection connection = new JDBConnection();
String sql = "select * from main_damage";
try {
ResultSet result = connection.executeQuery(sql);
while (result.next()){
String s1=result.getString(1);
String s2=result.getString(2);
String s3=result.getString(3);
String s4=result.getString(4);
System.out.println(s1+" "+s2+" "+s3+" "+s4);
}
}catch (Exception e){
e.printStackTrace();
}
finally {
connection.closeConnecstion();
}
}
}
对于常规JDBC的sql语句是一种“硬编码”的形式,当数据库相应的表字段出现变动的时候,我们就需要对java的源代码进行修改,然后重新编译、打包、上线,这样的过程不利于软件系统的维护和扩展。
待优化问题:
- 连接参数、SQL语句和硬编码:讲SQL语句配置在XML或者其他非Java的配置文件中,这样即使SQL发生变化,也不需要重新编译Java文件;
- 数据库的频繁连接和断开:使用数据库连接池来管理数据的连接;
- 查询结果集取数据的硬编码:使用一种机制,将查询出的结果集自动映射为JAVA对象,无需手动设置。
使用Mybatis框架可以逐步解决以上问题。
今天我们首先来学Mybatis的第一课:
一、Mybatis的介绍:
- MyBatis是Apache的一个Java开源项目,原名为iBatis(即Internet与abatis的结合),后因项目托管平台的迁移(由Goolge Code转移至GitHub)更名为MyBatis。Mybatis是一款支持动态SQL语句的持久层框架,支持的目的是让开发人员集中精力在SQL语句上,而不是数据库的配置和连接上。
- MyBatis可以将SQL语句配置在XML文件中,这就避免了JDBC在Java类中添加SQL语句的硬编码问题;通过MyBatis可以提供输入参数映射方式,讲参数自由灵活地配置在SQL语句配置文件中,解决了JDBC中参数在Java类中手工配置的问题;通过MyBatis的输出映射机制,讲结果集的检索自动映射成相应的Java对象或者Java对象集合,这就避免了JDBC中对结果集的手工检索;同时MyBatis还可以创建自己的数据库连接池,使用XML配置文件的形式,对数据库连接数据进行管理,避免了JDBC的数据库连接参数的硬编码问题。
总的来说:MyBatis的特点在于:采用配置文件动态管理SQL语句,并含有输入映射、输出映射机制以及数据库连接池配置的持久层框架。
二、MyBatis整体架构
MyBatis整体的构造由数据源配置文件、SQL映射配置文件、会话工厂、会话、执行器以及底层封装对象组成。
1、数据源配置文件
- 对于一个持久层框架,也就是负责连接数据库,并且对数据库进行操作的一套框架,连接数据库是最重要的一步。MyBatis框架对于数据库连接的配置信息,采用了配置“数据库连接池”的形式。所谓的“数据库连接池”又称为“数据源”,就是让数据库的配置信息从外部的某种配置文件(此处为xml文件)中读取,然后由一个独立处理数据库连接的程序来和数据库进行交互。这样我们的应用程序就不必关心数据库的配置信息,数据库的配置交由独立的模块管理和配置。
- 在MyBatis中,数据库的数据源是配置在SqlMapConfig.xml(文件名自定义)这个配置文件中的,其中配置了数据库驱动、数据库连接地址URL、数据库用户名和密码、事物管理等参数,如果对数据库连接池有性能的要求,还可以配置连接池的连接数和空闲时间等详细参数。
在项目中SqlMapConfig.xml配置文件的大致内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<!--使用JDBC事物管理-->
<transactionManager type="JDBC">
</transactionManager>
<!--数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybitas_test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
但是,我们如果在使用Spring MVC框架的整合中的时候,我们将会使用Spring MVC讲练数据库的连接池,我们就不需要再为MyBatis单独配置数据库连接池了。
2、SQL映射配置文件
- 在传统的JDBC开发模式中,SQL语句是硬编码在Java代码中的,而MyBatis框架讲SQL配置在独立的配置文件Mapper.xml文件中,作为Mapper配置文件。在这个配置文件中可以配置任何类型的SQL语句,包括select、update、delete和insert语句。
- 对于SQL语句执行所需要的参数,以及查询语句返回的结果集对象,都可以在Mapper.xml配置文件中配置。在输入参数方面MyBatis框架会根据配置文件中的参数配置,将组装参数的Java对象或Map对象中的相关字段与Mapper.xml中的参数配置做匹配,再把相关数据绑定在需要执行的SQL语句上;在查询语句输出结果的时候,会根据Mapper.xml中配置的结果集信息,将从数据库去除的数据字段,一一映射到相应的Java对象或Map对象中。也就是说,Mapper.xml配置文件,完成了对SQL语句的输入和输出参数的映射配置。
在项目中,Mapper.xml配置文件的大致内容如下:
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<select id="findUserById" parameterType="int" resultType="cn.com.mybatis.po.User">
select * from user where id= #{id}
</select>
<select id="findUser" resultType="cn.com.mybatis.po.User">
select * from user
</select>
</mapper>
在上诉的配置信息中,我们可以在mapper标签对中配置很对SQL语句。其中select标签对中包含了一段SQL查询的语句,其中parameterType指定了输入参数的类型,而resultType指定了输出结果映射的Java对象类型。可以看到其中的resultType的参数信息是一个JavaBean,相当于这一段select的结果参数配置表示将单挑记录映射成一个Java对象。
Mapper.xml的文件路径,一般会配置在数据源配置文件SqlMapConfig.xml中,其会随着数据库配置参数一起被加载。配置方法如下:
<mappers>
<mapper resource="config/UserMapper.xml"/>
</mappers>
3、会话工厂与会话
- 准备好了数据库连接处配置文件SqlMapConfig.xml,以及SQL映射配置文件Mapper.xml之后,需要相关的程序来读取并加载这些配置文件的信息。而MyBatis处理这些的核心对象就是“会话工厂” 和 “会话”。
- 在Mybatis中,“会话工厂”就是SqlSessionFactory类。工厂其实是一种会产生某种规范的对象的类的过程。SqlSessionFactory类会根据Resources资源信息加载对象,获取开发人员在项目中配置的数据库连接池配置文件SqlMapConfig.xml的信息,从而产生一种可以与数据库交互的会话实例类——SqlSession。就好像一个汽车工厂一样,给厂商一个汽车的详细配置说明书,这个厂商就可以生产出满足这个配置的汽车产品。SqlSessionFactory可以根据数据库配置信息产生出可以连接数据库并与其交互的SqlSession会话实例类。
- 早在我们配置SqlMapConfig.xml配置文件的时候,它也加载了Mapper.xml中的SQL语句的配置信息,这样我们就可以通过产生的SqlSession会话实例类,可以依照Mapper配置文件中的SQL配置,对数据库执行增删改查的操作。
三、MyBatis运行流程
四、MyBatis入门程序的搭建和测试
下面我们将亲自动手来编写一个MyBatis入门工程,该工程可研对数据库的某个字段进行查询。开发步骤如下:创建工程、引入依赖jar包、搭建日志输出环境、配置数据库连接池、创建持久层Java对象、编写Mapper配置文件、编写可运行的样例代码。
1.数据库的准备
首先我们使用MySQL数据库,创建一个mybatis_test的数据库,并在其中创建一张User的表,SQL代码如下:
/*
Navicat Premium Data Transfer
Source Server : localmysql
Source Server Type : MySQL
Source Server Version : 80016
Source Host : localhost:3306
Source Schema : mybitas_test
Target Server Type : MySQL
Target Server Version : 80016
File Encoding : 65001
Date: 11/02/2020 16:15:57
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(120) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`password` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`gender` varchar(5) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`email` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`province` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`city` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`birthday` date NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '张三', '111', '男', '1111@126.com', '河南省', '郑州市', '2014-06-28');
INSERT INTO `user` VALUES (2, '李四', '222', '男', '2222@126.com', '河北省', '邯郸市', '2020-02-28');
INSERT INTO `user` VALUES (3, '刘丽', '333', '女', '3333@126.com', '江苏省', '苏州市', '2020-02-22');
INSERT INTO `user` VALUES (4, '李丽', '444', '女', '4444@126.com', '四川省', '成都市', '2020-02-16');
SET FOREIGN_KEY_CHECKS = 1;
2. 搭建工程环境
2.1、 首先打开idea创建一个web工程,命名为MyBatis_testDemo.然后导入MyBatis框架所依赖的jar包:
我们这里添加log4j的包,目的在于输出日志文件,以便于在开发过程中对结果问题的分析和查询。
**2.2、**然后创建一下的class和配置文件:DataConnection.java、User.java、MybatisTest.java、UserMapper.xml、SqlMapConfig.xml
每一个文件内容如下:
DataConnection.java
package cn.com.mybatis.datasource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class DataConnection {
private String resource="SqlMapConfig.xml";
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
/**
* 返回可以与数据库交互的SqlSession对象
* @return
* @throws IOException
*/
public SqlSession getSqlSession() throws IOException{
//获取到xml文件
InputStream inputStream= Resources.getResourceAsStream(resource);
//创建会话工厂 传入MyBatis配置文件信息
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
sqlSession=sqlSessionFactory.openSession();
return sqlSession;
}
}
User.java
本文件建立的时候注意:必须定义无参构造函数,因为mybatis框架在最开始调用的时候,调用的是无参构造函数,如果不定义无参构造函数,将报找不到有参构造函数的error
package cn.com.mybatis.po;
import java.io.Serializable;
import java.sql.Date;
public class User implements Serializable {
private int id;
private String username;
private String password;
private String gender;
private String email;
private String province;
private String city;
private Date birthday;
public User(){ }
public User(int id, String username, String password, String gender, String email, String province, String city, Date birthday) {
super();
this.id = id;
this.username = username;
this.password = password;
this.gender = gender;
this.email = email;
this.province = province;
this.city = city;
this.birthday = birthday;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
MybatisTest.java
此处使用单元测试功能
package cn.com.mybatis.test;
import cn.com.mybatis.datasource.DataConnection;
import cn.com.mybatis.po.User;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
public class MybatisTest {
public DataConnection dataConnection=new DataConnection();
// 单元测试
@Test
public void TestSelect() throws IOException{
SqlSession sqlSession=dataConnection.getSqlSession();
List<User> userList=sqlSession.selectList("test.findUser");
for(User user:userList) {
System.out.println("姓名: " + user.getUsername());
System.out.println("性别: " + user.getGender());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
System.out.println("生日" + sdf.format(user.getBirthday()));
System.out.println("所在地 " + user.getProvince() + "/" + user.getCity());
}
}
}
UserMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<select id="findUserById" parameterType="int" resultType="cn.com.mybatis.po.User">
select * from user where id= #{id}
</select>
<select id="findUser" resultType="cn.com.mybatis.po.User">
select * from user
</select>
</mapper>
SqlMapConfig.xml文件
注意:在使用idea的时候,&符号idea不认识,需要把&修改为&;即可
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<environments default="development">
<environment id="development">
<!--使用JDBC事物管理-->
<transactionManager type="JDBC">
</transactionManager>
<!--数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybitas_test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--Mapper-->
<mappers>
<mapper resource="config/UserMapper.xml"/>
</mappers>
</configuration>
创建log4j.properties文件
log4j.rootLogger = debug,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
在以上文件全部构建完毕后,启动单元测试:TestSelect()
得到的结果如下:
查询到所有的user表中的数据,并输出在控制台中。
今天的学习就到此结束啦,MyBatis的出现使得我们在开发项目的过程中,
对于sql代码的硬编码问题得到了较大的改善,
在以后的学习Spring MVC后,MyBatis将会更加发挥它的优势所在。