MyBatis基础总结
1、JDBC
JDBC(Java Data Base Connectivity)用于执行SQL语句的Java API,可以为多种关系的数据库提供统一访问,有Java语言编写的类和接口组成,是Java访问数据库的标准规范。
获取jar包官网:https://downloads.mysql.com/archives/c-j/
JDBC开发步骤
// 1.注册JDCB驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.建立并获取数据库连接
Connection conn = DriverManager.getConnection(url,user,password)
// 3.创建JDBC Statement对象
Statement sta = conn.createStatement();
// 4.执行SQL语句,返回结果
// 执行增删改executeUpdate(String sql);返回值int
/* 查:executeQuery(String sql); 返回值ResultSet,使用next遍历,用 getXXX("字段名")获取字段信息。
*/
String sql = "";
<E> result = sta.executeUpdate(sql);
// 5.释放资源
预处理对象PreparedStatement
执行流程:
- 加载JDBC驱动
- 建立并获取数据库连接
- 创建JDBC Statement(PreparedStatement)对象
- 设置SQL语句的传入参数
- 执行SQL语句并获得查询结果
- 对查询结果进行转换处理并将处理结果返回
- 释放相关资源
String sql = "insert into sort(sid,sname) values(?,?)";
PreparedStatement psmt = conn.prepareStatement(sql);
psmt.setInt(1,6);
psmt.setString(2,"大五");
- 解决SQL语句的拼串传值问题
JDBC工具类
public class JDBCUtils {
public static Connection getConnection(){
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url,user,password);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn, Statement sta){
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(sta != null){
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Druid连接池
执行流程:
2、MyBatis
2.1 MyBatis框架介绍
- MyBatis是一个优秀的持久层框架,内部封装了JDBC
- MyBatis通过xml或注解的方式配置
- 采用ORM思想解决实体类和数据库映射问题,对JDBC进行封装,屏蔽了JDBC API底层访问细节。(让实体类和数据库表进行一一对应关系,不需要直接操作数据库表,直接操作表对应的实体类对象)
- O(Object):面向对象领域的JavaBean对象
- R(Relational):关系型数据库领域的表的结构
- M(Mapping):映射
- MyBatis执行流程(重要):加载配置->SQL解析->SQL执行->结果映射->释放连接
- 加载配置并初始化:从配置文件、或java代码注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
- 接收调用请求:调用Mybatis提高的API,传入SQL的ID和参数对象,将请求传递给下层的请求处理层进行处理。
- 处理操作请求:
- 根据SQL的id查找对应的MappedStatement对象
- 根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数
- 获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果
- 根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果
- 释放连接资源
- 返回处理结果:将最终的处理结果返回
2.2 MyBatis、xml方式配置
新建maven工程→导入mybatis坐标→编写mybatis配置文件→编写映射文件
导入mybatis坐标
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
编写mybatis配置文件config.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">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/xuzy/dao/userMapper.xml"/>
</mappers>
</configuration>
MyBatis配置文件标签
-
properties
- property:配置数据库连接(driver、url、username、password)
-
settings
- setting:配置全局参数:配置延迟加载
<settings> <!-- 设置懒加载 --> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> <!-- 缓存 --> <setting name="cacheEnabled" value="true"/> <!-- 设置日志记录 --> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
-
typeAliases
- typeAliase:单个实体类起别名
- type:要起别名的全限定类名
- alias:要起的别名
- package:批量起别名,在包下默认使用类名首字母小写的非限定类名作为别名
- typeAliase:单个实体类起别名
-
environments
- environment:环境集合数据对象,配置数据源和事务管理
- dataSource:type属性指定使用的数据库连接池(POOLED/UNPOOLED/JNDI)
- property:配置数据库连接
- transactionManager:事务管理
- dataSource:type属性指定使用的数据库连接池(POOLED/UNPOOLED/JNDI)
- environment:环境集合数据对象,配置数据源和事务管理
-
mappers
- mapper:映射SQL的xml配置文件(文件名要与dao的全限定名相同)
- resource:使用相对于类路径的mapper资源引用(引用xml资源)
- class:使用映射器接口实现类的完全限定类名,需要配置文件名和接口名称一致,并在位于同一目录下(映射包下接口名)
- package
- name:将包内的映射器接口全部注册为映射器(映射整个包所有接口)
- mapper:映射SQL的xml配置文件(文件名要与dao的全限定名相同)
编写SQL映射配置文件
<?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="cn.xuzy.dao.UserMapper">
<select id="selectUser" resultType="cn.xuzy.pojo.User">
select * from mybatis
</select>
<select id="selectUserById" resultType="cn.xuzy.pojo.User">
select * from user where id = #{id}
</select>
</mapper>
-
SQL语句配置标签:
// id属性必须和持久层(dao)接口的方法名相同,resultType可以直接引用实体类的全限定类名 <select>,<insert>,<delect>,<update>其标签的属性为 - resultType:指定结果集的类型(自定义对象需要写全限定类名) - parameterType:用于指定传入参数的类型(基本类型可以直接写类型的名称,自定义实体类需要写全限定类名)
- mapper:namespace属性:必须跟某个(dao)接口同名
- id:对应接口里的方法名,SQL语句实现其功能
- parameterType:用于指定传入参数的类型(基本类型可以直接写类型的名称,自定义实体类需要写全限定类名)
- resultType:结果集封装
- mapper:namespace属性:必须跟某个(dao)接口同名
-
SQL语句中使用#{}和${}
- #{}:表示一个占位符,通过#{}可以实现preparedStatement向占位符中设置值。#{}可以有效防止SQL注入。#{}可以接收基本类型值或pojo(自定义对象)属性值。语法#{对象.属性值}
- ** : 直 接 进 行 字 符 串 替 换 ∗ ∗ , 可 以 将 p a r a m e t e r T y p e 传 入 的 内 容 拼 接 在 S Q L 中 且 不 进 行 J D B C 类 型 转 换 。 {}:直接进行字符串替换**,可以将parameterType传入的内容拼接在SQL中且不进行JDBC类型转换。 :直接进行字符串替换∗∗,可以将parameterType传入的内容拼接在SQL中且不进行JDBC类型转换。{}可以接收基本类型值或pojo属性值
-
resultMap结果类型封装
resultMap标签可以建立查询的列名和实体类属性名称不一致时建立对应关系,从而实现封装。
标签属性:
- type:指定实体类的全限定类名。
- id:给定一个唯一标识,给select标签引用使用的。
子标签:
- id:指定主键字段,标签属性:
- column:指定数据库表列名
- property:指定实体类属性名称
- result:指定非主键字段
- 同id标签属性。
-
动态SQL语句
动态SQL指的是根据不同的查询条件,生成不同的SQL语句
- if
- choose(when, otherwise)
- trim(where, set)
- foreach
- collection:指定输入对象中的集合属性
- item:每次遍历生成的对象
- open:开始遍历时的拼接字符串
- close:结束时拼接的字符串
- separator:遍历对象之间需要拼接的字符串
动态SQL本质是SQL语句的拼接问题。
编写mabatis工具类
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
//读入配置文件
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
- 生命周期、作用域
- SqlSessionFactoryBuilder:最佳作用域是方法作用域,也就是局部方法变量
- SqlSessionFactory:声明周期在整个MyBatis应用中,最佳作用域是应用作用域。单例,因此用static代码块,在整个应用只执行一次new操作。
2.3 MaBatis 基于注解配置
- @Select()
- @Update()
- @Insert()
- @Delect()
- @Param:用于给方法参数起一个名字,与#{}括号里的名称一致
- 在方法只接受一个参数情况下,可以不使用@Param
- 在多个接受多个参数的情况下,建议使用@Param给参数命名
- 如果参数是JavaBean,则不能使用@Param
- @Param:用于给方法参数起一个名字,与#{}括号里的名称一致
@Select("select * from user")
public List<User> getAllUser();
//根据id删除用
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id")int id);
<!-- mybatis核心配置文件注入-->
<mappers>
<mapper class = "cn.xuzy.dao.UserDao"/>
</mappers>
- @Result():实现结果集封装
- id:主键字段
- column:非主键字段
- property:JavaBean要装配属性名
- one:需要使用@one注解
- select:
- many:需要使用@many注解
3、缓存
- 存在于内存中的临时数据
- 将用户经常查询的数据放在缓存中,用户去查询数据就不用从磁盘上查询,从缓存中查询,从而提高查询效率。
使用缓存好处
- 减少和数据库的交互次数,减少系统开销,提高系统效率
什么场景下不使用缓存
- 经常查询并且不经常改变的数据
4.1 Mybatis缓存
MyBatis系统默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启
- 二级缓存需要手动开启配置,基于namespace级别的缓存
- 为了提高扩展性,MyBatis定义了缓存接口Cache。通过实现Cache接口来自定义二级缓存
一级缓存(本地缓存)
- 与数据库的同一次会话期间查询到的数据会放到本地缓存中
- 以后如果需要获取相同的数据,直接从缓存中获取,不需要去查询数据库
二级缓存
- 二级缓存也叫全局缓存
- 基于namespace级别的缓存,一个名称空间对应一个二级缓存
- 工作机制
- 一个会话查询一条数据,这个数据会放到当前会话的一级缓存,如果会话关闭,这个会话对应的一级缓存数据会被保存到二级缓存,新的会话就可以从二级缓存中获取数据
<setting name="cacheEnabled" value="true"/>
4、MyBatis执行流程
4.1 底层运行逻辑
MyBatis核心类
- SqLSessionFactoryBuilder:用于创建一个SqlSessionFactory
- SqlSessionFactory:
- 每一个MyBatis应用都是以一个SqlSessionFactory的实例为中心。
- 他可以有SqlSessionFactoryBuilder从xml配置中构建SqlSessionFactory实例。
- SqlSessionFactory的最佳作用域是应用作用域,建议使用单例模式或静态单例模式。
- 多个数据看应配置多个SqlSessionFactory与之一一对应。
- SqlSession:
- SqlSession是一个接口,优良实现类,默认使用DefaultSqlSession, SqlSessionManager
- SqlSession通过内部的执行器(Executor)来对数据进行CRUD
- 线程不安全,每次操作完数据库后斗鱼调用close对其进行关闭。通过try-finally
- Executor:
- MappedStatement:
- 存放SQL映射文件中的信息,包括sql语句、输入参数、输出参数等,一个MappedStatememt对象。
MyBatis功能框架
MyBatis功能架构分为三层:
- **API接口层:**提供给外部使用的接口API,通过这些API操作数据库。接口层接收到调用请求就会调用数据处理层来完成具体是数据处理
- **数据处理层:**负责CRUD和执行结果映射
- **基础支撑层:**负责最基础功能支撑,包括连接管理、事务管理、配置加载和缓存处理
4.2 详细执行流程
参考文献
- 【狂神说Java】Mybatis最新完整教程IDEA版通俗易懂:https://www.bilibili.com/video/BV1NE411Q7Nx?from=search&seid=3950126876256805284
- Mybatis工作流程及其原理与解析:https://blog.csdn.net/u010890358/article/details/80665753
- Mybatis实现原理深入解析:https://blog.csdn.net/xudan1010/article/details/53435018