一、MyBatis介绍
MyBatis历史
-
MyBatis是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了Google Code,随着开发团队转投Google Code旗下, iBatis3.x 正式更名为MyBatis ,代码于2013年11月迁移到Github)
-
iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis 提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
MyBatis简介
- MyBatis是一个优秀的基于Java的持久层框架,它内部封装了JDBC操作,使开发者只需要关注SQL语句的本身,而不需要花费精力去处理加载驱动、创建连接、创建执行者等复杂的操作。
- MyBatis通过xml或者注解的方式将要执行的各种Statement配置起来,并通过Java对象和Statement中SQL的动态参数进行映射生成最终要执行的SQL语句
- 最后MyBatis框架执行完SQL并将结果映射为Java对象并返回,采用ORM思想解决了实体和数据库映射的问题,对JDBC进行了封装,屏蔽了JDBC API底层访问细节,使我们不用与JDBC API打交道,就可以完成对数据库的持久化操作
MyBatis官网
https://github.com/mybatis/mybatis-3/
二、为什么要使用MyBatis?
传统JDBC操作分析
public class Demo{
public static void main(String[] args) throws Exception{
Class.forName('com.mysql.cj.jdbc.Driver');
// 数据库连接信息
String url = "jdbc:mysql://localhost:3306/test";
String username = "root";
String password = "123456";
// 获取连接
Connection connection = DriverManager.getConnection(url,username,password);
// 操作sql语句
PreparedStatement preparedStatement = connection.prepareStatement("Select * FROM student");
// 执行sql语句
ResultSet resultSet = preparedStatement.executeQuery();
// 操作数据
while(resultSet.next()){
Student student = new Student();
student.setName(resultSet.getSring("name"));
student.setAge(resultSet.getSring("age"));
student.setGender(resultSet.getSring("gender"));
System.out.println(student);
}
// 释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
}
原始jdbc操作的分析
- 频繁创建和销毁数据库的连接会造成系统资源浪费从而影响系统性能。
Class.forName('com.mysql.cj.jdbc.Driver'); // 数据库连接信息 String url = "jdbc:mysql://localhost:3306/test"; String username = "root"; String password = "123456"; // 获取连接 Connection connection = DriverManager.getConnection(url,username,password);
-
sql 语句在代码中硬编码,如果要修改 sql 语句,就需要修改 java 代码,造成代码不易维护。
// 操作sql语句 PreparedStatement preparedStatement = connection.prepareStatement("Select * FROM student");
-
查询操作时,需要手动将结果集中的数据封装到实体对象中。
// 执行sql语句 ResultSet resultSet = preparedStatement.executeQuery(); // 操作数据 while(resultSet.next()){ Student student = new Student(); student.setName(resultSet.getSring("name")); student.setAge(resultSet.getSring("age")); student.setGender(resultSet.getSring("gender")); System.out.println(student); }
-
增删改查操作需要参数时,需要手动将实体对象的数据设置到 sql 语句的占位符。
解决方案
- 使用数据库连接池初始化连接资源。
-
将 sql 语句抽取到配置文件中。
-
使用反射、内省等底层技术,将实体与表进行属性与字段的自动映射
选择MyBatis
- MyBatis是一个持久层框架技术解决方案
- 框架是一款半成品软件,我们只需要基于这个半成品软件继续开发,来完成我们个性化的需求
- MyBatis的ORM
- ORM(Object RelationMapping) 对象关系映射
- 对象关系映射指的是持久化数据和实体对象的映射模式,表里的数据和JavaBean实例相互交流映射,就是ORM
映射规则:
- 数据表 <--> 类
- 表的字段 <--> 类的属性
- 表的数据 <--> 实例对象
三、MyBatis入门体验
1、创建Maven工程,添加依赖
2、创建学生数据库,并创建学生表,字段有[id,name,age]
3、创建一个实体Student学生实体类【学生类的属性和数据库字段对应】,并提供构造方法、get和set方法以及toString方法
4、在resources目录下创建MyBatis的映射配置文件StudentMapper.xml
5、在resources目录下创建核心配置文件MyBatisConfig.xml
6、编写测试类,测试数据
1、创建Maven工程,添加依赖
打开IDEA,创建Maven工程
添加依赖
<dependencies>
<!--数据库连接依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- MyBatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!-- 日志依赖 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
2、创建学生数据库,并创建学生表,字段有[id,name,age]
# 创建数据库
CREATE DATABASE student_db;
# 使用数据库
use student_db;
# 创建数据表
CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(10),age INT);
# 插入数据
INSERT INTO student(name,age) VALUES('张三',23),('李四',24),('王五',25);
查看数据库查看数据
3、创建一个实体Student学生实体类【学生类的属性和数据库字段对应】,并提供构造方法、get和set方法以及toString方法
/**
* 学生实体类
* 字段和数据库对应
*/
public class Student {
/**
* id
*/
private Integer id;
/**
* 学生姓名
*/
private String name;
/**
* 学生年龄
*/
private String age;
/**
* 无参数构造方法
*/
public Student() {
}
/**
* 有参数构造方法
*/
public Student(Integer id, String name, String age) {
this.id = id;
this.name = name;
this.age = age;
}
// get和set方法
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
/**
* toString方法
*/
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
4、在resources目录下创建MyBatis的映射配置文件StudentMapper.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">
<!-- namespace -->
<mapper namespace="StudentMapper">
<!-- id唯一的标识 resultType:将获取数据库的数据封装到哪个实体类中-->
<select id="selectAll" resultType="cn.guan.domain.Student">
SELECT id,name,age FROM student
</select>
</mapper>
5、在resources目录下创建核心配置文件MyBatisConfig.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>
<!-- 配置环境 default :标识将来采取哪个配置 environment的id对应 -->
<environments default="mysql">
<environment id="mysql">
<!-- 相关事务的支持 JDBC代表采用默认的事务 -->
<transactionManager type="JDBC"/>
<!-- dataSource:数据源 POOLED 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/student_db?characterEncoding=utf8&serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="12122"/>
</dataSource>
</environment>
</environments>
<!-- 加载隐式文件-->
<mappers>
<!-- 加载前面编写的SQL语句的文件 -->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
6、编写测试类,测试数据
public class MyBatisTest {
/**
* 使用MyBatis查询所有数据
*/
@Test
public void selectAll() throws IOException {
// 1、加载核心配置文件 MyBatisConfig.xml 通过工具类Resources加载核心配置文件 org.apache.ibatis.io.Resources; 返回一个字节流输入对象
InputStream inputStream = Resources.getResourceAsStream("MyBatisConfig.xml");
// 2、获取SqlSession工厂对象 通过工厂构造者对象获取
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSession工厂对象获取SqlSession对象 sqlSession执行功能的对象
SqlSession sqlSession = factory.openSession();
// 4、执行映射配置文件中的sql语句,并接收结果 selectList(str) str:写入namespace的名称.id名称
List<Student> list = sqlSession.selectList("StudentMapper.selectAll");
// 5、处理结果
for (Student s : list) {
System.out.println(s);
}
// 6、释放资源
sqlSession.close();
inputStream.close();
}
}
控制台结果
相关类和方法解读:
1、Resources
org.apache.ibatis.io.Resources:加资源的的工具类
ibatis是Mybatis的前身,改了名后叫MyBatis
InputStream getResourceAsStream(String fileName):通过类加载器返回指定资源的字节输入流
InputStream in = Resources.getResourceAsSteram("MyBatis核心配置文件路径");
2、SqlSessionFactoryBuilder
org.apache.ibatis.session.SqlSessionFactoryBuilder:获取SqlSessionFactory工厂对象的功能类
SqlSessionFactory build(InputStream in) :通过指定资源字节输入流获取SqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
3、SqlSessionFactory
org.apache.ibatis.session.SqlSessionFactory:获取SqlSession构建者对象的工厂接口
SqlSession openSession():获取SqlSession构建者对象,并开启手动提交事务
SqlSession openSession(boolean autoCommit):获取SqlSession构建者对象,如果参数为true,则开启自动提交事务
SqlSession sqlSession = factory.openSession();
// 开启自动事务提交
SqlSession sqlSession = factory.openSession(true);
4、SqlSession
org.apache.ibatis.session.SqlSession:构建者对象接口,用于执行SQL、管理事务、接口代理等。
List<E> selectList(String statement,Object paramter):执行查询语句,返回List集合
T selectOne(String statement,Object paramter):执行查询语句,返回一个结果对象
int insert(String statement,Object paramter):执行插入语句,返回影响行数
int upadte(String statement,Object paramter):执行更新语句,返回影响的行数
int delete(String statement,Object paramter):执行删除语句,返回影响行数
void commit():提交事务
void rollback():回滚事务
T getMapper(Class<T> cls):获取指定接口的代理实现类对象
void close():释放资源
映射配置文件介绍XXXMapper.xml
- MyBatis的真正强大的在它的语句映射,映射器XML文件很简单
- MyBatis致力于减少使用成本,让用户更专注于SQL代码
首先我们先体验下增删改查,然后在来详细介绍个个的作用
环境: IDEA
数据库 mysql 8
项目工程结构
MyBatisConfig.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核心根标签 -->
<configuration>
<!-- 配置开发环境:default属性指定使用哪个配置,environment的id属性对应 -->
<environments default="development">
<environment id="development">
<!-- 指定事务:JDBC代表采用默认的事务 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_db?serverTimezone=UTC&characterEncoding=UTF-8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="12122"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
映射配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!-- MyBatis的DTD约束 -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- mapper:核心根标签
namespace属性:命名空间,当我们没有用接口的时候,我们可以namespace.方法名(我们给标签设置的id)
-->
<mapper namespace="UserMapper">
<!-- 查询所有数据
MyBatis 的基本原则之一是:在每个插入、更新或删除操作之间,通常会执行多个查询操作。
select:查询功能的标签
id:唯一属性
resultType属性:指定结果映射对象类型
parameterType属性:指定参数映射对象类型
-->
<select id="selectAll" resultType="cn.guan.domain.User">
select * from user
</select>
<!--根据id查询数据 -->
<select id="selectById" parameterType="integer" resultType="cn.guan.domain.User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 根据id更新数据 -->
<update id="updateById" parameterType="cn.guan.domain.User">
UPDATE user set name = #{name},age = #{age} WHERE id = #{id}
</update>
<!-- 根据id删除数据-->
<delete id="deleteById" parameterType="integer">
DELETE FROM user WHERE id = #{id}
</delete>
<insert id="addInfo" parameterType="cn.guan.domain.User">
INSERT into user (name,age) VALUES(#{name},#{age})
</insert>
</mapper>
Test测试类
package cn.guan;
import cn.guan.domain.User;
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;
import java.util.List;
public class Test {
public static void main(String[] args) throws IOException {
// 加载核心配置文件
InputStream in = Resources.getResourceAsStream("MyBatisConfig.xml");
// 通过构建者对象获取工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 通过工厂对象获取会话对象
SqlSession sqlSession = factory.openSession();
// 调用方法
// 调用查询所有方法
List<User> list = sqlSession.selectList("UserMapper.selectAll");
System.out.println("-------------------查询所有结果-------------------------------");
System.out.println(list);
User myUser = new User("insertData",14);
// 插入一条记录
int insertResult = sqlSession.insert("UserMapper.addInfo", myUser);
System.out.println("\n\n-------------------插入记录结果-------------------------------");
System.out.println(insertResult);
// 根据id查询信息
User user = sqlSession.selectOne("UserMapper.selectById",2);
System.out.println("\n\n-------------------根据ID查询信息结果-------------------------------");
System.out.println(user);
// 根据id修改信息我们修改第一条数据 id为1
User u = new User(1,"newName",66);
// 返回影响的行数
int updateResult = sqlSession.update("UserMapper.updateById", u);
System.out.println("\n\n-------------------根据ID修改信息结果-------------------------------");
System.out.println(updateResult);
// 根据id删除员工信息 我们删除id为3的数据
int deleteResult = sqlSession.delete("UserMapper.deleteById", 3);
System.out.println("\n\n-------------------根据ID删除息结果-------------------------------");
System.out.println(deleteResult);
// 释放资源
sqlSession.close();
in.close();
}
}
结果
1、select标签
- select标签是查询功能标签
- 属性参考官方
2、insert、update、Delte标签
- insert是新增功能标签
- update是修改功能标签
- delete是删除功能标签
通用属性:参考官方
核心映射配置文件MyBatisConfig.xml解读
- 核心配置文件包含了MyBatis最核心的设置和属性信息,如数据库的连接、事务、连接池信息等。
- configuration:核心根标签
- propreties:引入数据库连接信息配置文件标签
- typeAliases:起别名标签。
- environments:配置数据库环境标签
- environment:配置数据库信息标签
- transactionManager:事务管理标签
- dataSource:数据源标签
- property:数据库连接信息标签
- mapper:引入映射配置文件标签
<?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>
<!-- 配置环境 default :标识将来采取哪个配置 environment的id对应 -->
// environments配置数据库环境
<environments default="mysql">
<environment id="mysql">
<!-- 相关事务的支持 JDBC代表采用默认的事务 -->
<transactionManager type="JDBC"/>
<!-- dataSource:数据源 POOLED 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db1?characterEncoding=utf8&serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="12122"/>
</dataSource>
</environment>
</environments>
<!-- 加载隐式文件-->
<mappers>
<!-- 加载前面编写的SQL语句的文件 -->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
抽取数据源到properties的使用
1、创建jdbc.properties,里面编写数据源相关信息
在resources创建jdbc.properties
然后修改MyBatisConfig.xml核心配置文件的dataSource标签
首先引入properties标签,通过resource指定刚刚创建的配置文件
我们跑下刚刚程序,没有报错说明配置成功
二、MyBatis接口代理方式
在我们上面内容中,我们都是使用命名空间的id唯一标识来调用方法的,我们接下来改进这种方式,使用接口代理方式
有一些规则我们要注意
- 1、映射配置文件中的名称空间必须和Dao层接口的全类名相同
- 2、映射配置文件中的增删改查标签的id属性必须和Dao层接口的方法名相同
- 3、映射配置文件中的增删改查标签的parameterType属性必须和Dao层接口的方法的参数相同
- 4、映射配置文件中的增伤改查标签的resultType属性必须和Dao层接口的方法返回值相同
1、添加dao层,创建UserMapper接口,里面编写逻辑
记得修改核心配置文件的mapper标签的映射配置文件指向
package cn.guan.dao;
import cn.guan.domain.User;
import java.util.List;
/**
* 持久层接口
*/
public interface UserMapper {
/**
* 查询当前表所有记录
*/
List<User> selectAll();
/**
* 根据id查询一条记录
*/
User selectById();
/**
* 根据id修改信息
*/
Integer updateById(Integer id);
/**
* 根据id删除信息
*/
Integer deleteById(Integer id);
/**
* 添加一条记录
*/
Integer addInfo(User user);
}
2、修改测试类
// 获取操作对象 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
在这里我们获取操作对象,可以很好的操作接口的方法
public class Test {
public static void main(String[] args) throws IOException {
// 加载核心配置文件
InputStream in = Resources.getResourceAsStream("MyBatisConfig.xml");
// 通过构建者对象获取工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 通过工厂对象获取会话对象
SqlSession sqlSession = factory.openSession();
// 获取操作对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 调用方法
// 调用查询所有方法
List<User> users = mapper.selectAll();
System.out.println("-------------------查询所有结果-------------------------------");
System.out.println(users);
// 插入一条记录
User myUser = new User("insertData",14);
Integer insertResult = mapper.addInfo(myUser);
System.out.println("\n\n-------------------插入记录结果-------------------------------");
System.out.println(insertResult);
// 根据id查询信息
User user = mapper.selectById(2);
System.out.println("\n\n-------------------根据ID查询信息结果-------------------------------");
System.out.println(user);
// 根据id修改信息我们修改第一条数据 id为1
User u = new User(1,"newName",66);
// 返回影响的行数
Integer updateResult = mapper.updateById(u);
System.out.println("\n\n-------------------根据ID修改信息结果-------------------------------");
System.out.println(updateResult);
// 根据id删除员工信息 我们删除id为3的数据
Integer deleteResult = mapper.deleteById(3);
System.out.println("\n\n-------------------根据ID删除息结果-------------------------------");
System.out.println(deleteResult);
// 释放资源
sqlSession.close();
in.close();
}
}
3、运行测试
运行成功!
这里包含了一个知识点:动态代理
-
同过动态代理开发模式,我们只编写了一个接口,不写实现类,我们通过SqlSession的getMaper()方法最终获取到了org.apache.ibatis.binding.MapperProxy代理对象,然后执行功能,而这个代理对象正式MyBatis使用了JDK的动态代理技术,帮我们生成了代理实现类对象。从而可以进行相关持久化操作。
-
(相关细节在后续源码解析在来详细解释)