本章内容
- MyBatis的概念,ORM的概念
- 原始JDBC连接数据库的方法以及缺点
- Mybatis的常用功能
- 快速构建Mybatis工程
- MyBatis中重要核心对象
一、MyBatis概述
1.1 什么是MyBatis?
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
- MyBatis是java程序对数据库进行增删改查的一个工具
- java对数据库进行增删改查的工具很多,较之于其他工具,mybatis容易上手,而且开发起来也很简单,同时与spring的组合也非常容易
- 目前各大互联网公司多是使用mybatis
1.2 原始JDBC连接数据库
1.2.1 原始JDBC数据处理过程
连接数据库需要经过的步骤
- 加载数据库驱动
- 创建并获取数据库链接
- 设置sql语句
- 创建jdbc statement对象
- 设置sql语句中的参数(使用preparedStatement)
- 通过statement执行sql并获取结果
- 对sql执行结果进行解析处理
- 释放资源(resultSet、preparedstatement、connection)
具体代码
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1、加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//2、通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/crm?characterEncoding=utf-8", "root", "root");
//3、定义sql语句 ?表示占位符
String sql = "select * from t_user where username = ?";
//4、获取预处理statement
preparedStatement = connection.prepareStatement(sql);
//5、设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "金庸");
//6、向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
//7、遍历查询结果集
while(resultSet.next()){
System.out.println(resultSet.getInt("id")+" "+resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//8、释放资源
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
1.2.2 原始JDBC数据处理的特点
- 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题
- Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码
- xml配置文件解决 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护
- 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便
1.3 ORM框架概念
什么是ORM?
ORM(O/R Mapping:对象关系映射)。它是一种将内存中的对象保存到关系型数据库中的技术;主要负责实体域对象的持久化,封装数据库访问细节;提供了实现持久化层的另一种模式,采用映射元数据(XML)来描述对象-关系的映射细节,使得ORM中间件能在任何一个Java应用的业务逻辑层和数据库之间充当桥梁
二、MyBatis的功能
功能介绍
API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理
数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作
基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑
三、快速开始Mybatis
操作步骤
- 导入MyBatis包
- 导入MySQL驱动包
- 创建表的实体类, 例如: User(id, username……)
- 编写MyBatis的核心配置文件,例如: mybatis-configuration.xml
- 编写映射文件, 例如: UserMapper.xml
- 编写测试来完成数据库CRUD操作
3.1 第一步:准备测试数据库和表
首先准备好数据库和表
DROP DATABASE IF EXISTS `crm`;
CREATE DATABASE `crm`;
use `crm`;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_tel` varchar(11) COLLATE utf8mb4_unicode_ci NOT NULL,
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`registration_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8;
INSERT INTO `t_user` VALUES ('1', '13880000001', '金庸', '0b4e7a0e5fe84ad35fb5f95b9ceeac79', '2018-12-15 06:54:16'),
('2', '13880000002', '张三丰', '875f26fdb1cecf20ceb4ca028263dec6', '2018-12-15 06:54:16'),
('3', '13880000003', '张无忌', 'c1f68ec06b490b3ecb4066b1b13a9ee9', '2018-12-15 06:54:16'),
('4', '13880000004', '黄蓉', '980ac217c6b51e7dc41040bec1edfec8', '2018-12-15 06:54:16'),
('5', '13880000005', '郭靖', 'cd87cd5ef753a06ee79fc75dc7cfe66c', '2018-12-15 06:54:16'),
('6', '13880000006', '周伯通', 'eed8cdc400dfd4ec85dff70a170066b7', '2018-12-15 06:54:16'),
('7', '13880000006', '杨过', '594f803b380a41396ed63dca39503542', '2018-12-17 17:05:40');
表结构为
3.2 第二步:建立maven工程
1.建立工程
Maven是一个工程构建工具,简单来说,就是我们的Java工程要按照Maven规定的模式创建,java源文件应该放在什么位置,配置文件,测试文件该放在什么位置等等都有规定,maven工程目录结构为
2.修改pom.xml文件,导入相关包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yingside</groupId>
<artifactId>mybatisdemo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--mysql数据库驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--引入mybatis包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--引入junit测试包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
在<dependencies></dependencies>
标签中加入相应包的Maven标签,就能自动引入了
3.3 第三步:配置Mybatis文件
上面主要是和maven相关的,接下来才是MyBatis最重要的内容 我们要使用MyBatis,肯定需要相关配置,现在主流的其实就两种XML配置文件,以及注解配置,我们先来看一下通过XML配置文件实现的过程 下面是整个工程的结构
3.3.1 在resources目录中加入mybatis-configuration.xml文件
mybatis-configuration.xml文件是整个MyBatis的全局配置文件
<?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">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/crm"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
3.4 第四步:定义表所对应的实体类
package com.yingside.bean;
public class User {
private Integer id;
private String userTel;
private String username;
private String password;
private String registrationTime;
//此处省略getter与setter方法
}
3.5 第五步:定义操作 t_user 表的sql映射文件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">
<!-- 这个XML文件其实就相当于我们三层架构中的DAO层的实现类xxxDaoImpl,如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。
也就是说,有了这个配置文件,至少之前原始JDBC中经常出现的Connection,PreparedStatement,ResultSet这些接口不需要你再创建了
当然要编写这个文件,需要对<mapper>标签中出现的属性和标签都要熟悉,不过没有必要去一一熟悉,用到什么我们再去查询就行了
-->
<!-- 为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
例如namespace="om.yingside.mapper.UserMapper"就是com.yingside.mapper(包名)+UserMapper(UserMapper.xml文件去除后缀)
-->
<mapper namespace="com.yingside.mapper.UserMapper">
<!--
根据 id 查询 user 表中的数据
id:唯一标识符,此文件中的id值不能重复,简单来说,就是DAO层中的方法名
resultType:返回值类型,一条数据库记录也就对应实体类的一个对象,注意现在要跟上全名(包名+类名)
parameterType:参数类型,也就是查询条件的类型
#{}表示一个占位符即?,在使用时不需要关心参数值的类型,mybatis会自动进行java类型和jdbc类型的转换。
-->
<select id="getUser" parameterType="int"
resultType="com.yingside.bean.User">
select * from t_user where id=#{id}
</select>
</mapper>
3.6 第六步:在mybatis-configuration.xml配置文件中注册UserMapper.xml文件
mybatis-configuration.xml文件的<configuration></configuration>
标签中加入<mappers></mappers>
标签。通过下面的截图,注意<mappers></mappers>
的位置
<!-- 注册UserMapper.xml文件,
UserMapper.xml位于com.yingside.mapper这个包下,
所以resource写成com/yingside/mapper/UserMapper.xml-->
<mappers>
<mapper resource="com/yingside/mapper/UserMapper.xml" />
</mappers>
3.7 测试
package com.yingside.test;
import com.yingside.bean.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import java.io.InputStream;
public class Test {
SqlSession sqlSession = null;
@Before
public void init(){
//mybatis全局配置文件
String resource = "mybatis-configuration.xml";
//加载全局配置文件
InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
//创建SqlSession工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//通过工厂生成sqlSession
sqlSession = factory.openSession();
}
@org.junit.Test
public void testGetUser(){
/*这个字符串由 userMapper.xml 文件中 两个部分构成
<mapper namespace="com.yingside.mapper.UserMapper"> 的 namespace 的值
<select id="getUser" > id 值
其实就相当于之前Dao层中xxxDaoImpl.getUser()方法
*/
String stmt = "com.yingside.mapper.UserMapper.getUser";
//传入字符串以及参数id
User user = sqlSession.selectOne(stmt,1);
System.out.println(user);
//关闭sqlSession
sqlSession.close();
}
}
测试运行
User{id=1, userTel='null', username='金庸', password='0b4e7a0e5fe84ad35fb5f95b9ceeac79', registrationTime='null'}
User对象确实成功的获取到了,并且id,username和password属性都成功的取得,但是userTel和registrationTime却是null,这明显是有问题的,不过至少现在已经成功的获取了数据库中的内容,其他的问题,我们下面的再解决
四、IDEA开发工具不能找到XML文件的问题
如果你按照步骤一步一步做下来,结果还是有问题,报了下面的错误,那么很有可能就是你IDEA工具自身的问题
- org.apache.ibatis.exceptions.PersistenceException:
- ### Error building SqlSession.
- ### The error may exist in com/yingside/mapper/UserMapper.xml
- ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/yingside/mapper/UserMapper.xml
- ...
简单来说,这个错误就是告诉你没有找到相应的xml文件,但是我们在配置文件中确实也配置了UserMapper.xml的位置.
导致这个问题的原因是: 某些版本的IDEA不会编译src的java目录的xml文件
解决思路就是:将IDEA maven项目中src源代码下的xml等资源文件编译进classes文件夹
体操作方法就是:配置maven的pom.xml文件配置,在节点下添加代码
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
五、一些MyBatis的配置文件说明
5.1 MyBatis的核心配置文件
5.2 MyBatis的映射文件
5.3 MyBatis的核心对象
使用MyBatis框架时,主要涉及两个核心对象:SqlSessionFactory和SqlSession
5.3.1 SqlSessionFactory
SqlSessionFactory是MyBatis框架中十分重要的对象,它是单个数据库映射关系经过编译后的内存镜像,其主要作用是创建SqlSession。 SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来构建,而SqlSessionFactoryBuilder则可以通过XML配置文件或一个预先定义好的Configuration实例构建出SqlSessionFactory的实例。
通过XML配置文件构建出的SqlSessionFactory:
InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory对象是线程安全的,它一旦被创建,在整个应用执行期间都会存在。如果我们多次的创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。 为此,通常每一个数据库都会只对应一个SqlSessionFactory,所以在构建SqlSessionFactory实例时,建议使用单列模式。
5.3.2 SqlSession
SqlSession是MyBatis框架中另一个重要的对象,它是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作。 每一个线程都应该有一个自己的SqlSession实例,并且该实例是不能被共享的。同时,SqlSession实例也是线程不安全的,因此其使用范围最好在一次请求或一个方法中, 绝不能将其放在一个类的静态字段、实例字段或任何类型的管理范围(如Servlet的HttpSession)中使用。 使用完SqlSession对象后要及时关闭,通常可以将其放在finally块中关闭。
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
// 此处执行持久化操作
} finally {
sqlSession.close();
}
5.3.3 SqlSession的查询方法
- <T> T selectOne(String statement);参数statement是在配置文件中定义的<select> 元素的id。使用该方法会返回查询结果的一条泛型对象。
- <T> T selectOne(String statement, Object parameter);参数statement是在配置文件中定义的<select> 元素的id,parameter是查询所需的参数。使用该方法会返回查询结果的一条泛型对象。
- <E> List<E> selectList(String statement);参数statement是在配置文件中定义的<select> 元素的id。使用该方法,会返回查询结果的泛型对象的集合。
- <E> List<E> selectList(String statement, Object parameter);参数statement是在配置文件中定义的<select> 元素的id,parameter是查询所需的参数。使用该方法,会返回查询结果的泛型对象的集合。
- <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);参数statement是在配置文件中定义的<select> 元素的id,parameter是查询所需的参数,rowBounds是用于分页的参数对象。 使用该方法,会返回查询结果的泛型对象的集合。
- void select(String statement, Object parameter, ResultHandler handler);参数statement是在配置文件中定义的<select> 元素的id,parameter是查询所需的参数,ResultHandler 是用于处理查询返回的复杂结果集,通常用于多表查询。
5.3.4 SqlSession中的增删改方法
- int insert(String statement);参数statement是在配置文件中定义的 元素的id,返回SQL语句所影响的行数
- int insert(String statement, Object parameter);参数statement是在配置文件中定义的<insert> 元素的id,parameter是插入所需要参数。返回SQL语句所影响的行数
- int update(String statement);参数statement是在配置文件中定义的 元素的id,返回SQL语句所影响的行数
- int update(String statement, Object parameter);参数statement是在配置文件中定义的<update> 元素的id,parameter是更新所需要的参数。返回SQL语句所影响的行数
- int delete(String statement);参数statement是在配置文件中定义的<delete> 元素的id,返回SQL语句所影响的行数
- int delete(String statement, Object parameter);参数statement是在配置文件中定义的<delete> 元素的id,parameter是删除所需要的参数。返回SQL语句所影响的行数
5.3.5 SqlSession的其它方法
- void commit(); 提交事务的方法,很重要增删改等操作别忘记它
- void rollback(); 回滚事务的方法
- void close(); 关闭SqlSession对象
- <T> T getMapper(Class<T> type); 返回Mapper接口的代理对象
- Connection getConnection(); 获取JDBC数据库连接对象的方法