了解MyBatis框架
Posted 你这家伙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了了解MyBatis框架相关的知识,希望对你有一定的参考价值。
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
JDBC编程存在的问题
在此之前我们了解的JDBC的操作为: 1. 首先创建数据库连接池DataSource 2. 通过DataSource获取数据库连接Connection 3. 编写要执行带“?”占位符的SQL语句 4. 通过Connection及SQL创建操作命令对象Statement 5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值 6. 执行SQL语句 7. 处理结果集 8. 释放资源存在问题:
对用不同业务来说,他的CRUD操作类型基本上都是以上的步骤,只有如下部分是不一样的:
- 带占位符的SQL语句
- 替换占位符:一般使用基础类型或Java对象,需要明确替换哪个占位符,哪个值来替换
- 如果是查新。一般会将结果集转换为Java对象,需要提供转换的急Java类型,及与结果集字段的映射关系
可以看出少量的代码真正用于业务功能,大部分的代码都是样板代码。不过,这些样板代码非常重要,清理资源和处理错误确保了数据访问的健壮性,避免了资源的泄露。
解决方案
- 最简单的,涉及工具类提供统一的功能:获取数据库连接,释放资源
- 使用模版设计模式,父类的模板方法提供统一的逻辑,子类提供不同实现。但这部分统一代码逻辑都会比较复杂。
- 更进一步的考虑,其实可以通过 AOP 技术,自动的生成代理类,代理类的方法中织入了统一的样板代码。
框架会采用第三种解决方案,自动的生成样板代码,我们只需要提供 sql ,要替换占位符的数据,返回结果集要转换的 java 类型
ORM框架
ORM(Object Relational Mapping),即对象关系映射。在面向对象编程语言中,将关系型数据库中的数据与对象建立起映射关系,进而自动的完成数据与对象的互相转换:
- 将输入数据(即传入对象)+SQL 映射成原生 SQL
- 将结果集映射为返回对象,即输出对象
ORM 把数据库映射为对象:
数据库表(table)–> 类(class)
记录(record,行数据)–> 对象(object)
字段(field) --> 对象的属性(attribute)
常见的ORM框架
常见的ORM框架有Mybatis和Hibernate
Mybatis
Mybatis是一种典型的半自动的 ORM 框架,所谓的半自动,是因为还需要手动的写 SQL 语句,再由框
架根据 SQL 及 传入数据来组装为要执行的 SQL。其优点为:
- 因为由程序员自己写 SQL,相对来说学习门槛更低,更容易入门。
- 更方便做 SQL的性能优化及维护。
- 对关系型数据库的模型要求不高,这样在做数据库模型调整时,影响不会太大。适合软件需求变更
比较频繁的系统,因此国内系统大部分都是使用如 Mybatis 这样的半自动 ORM 框架。
其缺陷为:
不能跨数据库,因为写的 SQL 可能存在某数据库特有的语法或关键词
Hibernate
Hibernate是一种典型的全自动 ORM 框架,所谓的全自动,是 SQL 语句都不用在编写,基于框架的
API,可以将对象自动的组装为要执行的 SQL 语句。其优点为:
- 全自动 ORM 框架,自动的组装为 SQL 语句。
- 可以跨数据库,框架提供了多套主流数据库的 SQL 生成规则。
其缺点为:
学习门槛更高,要学习框架 API 与 SQL 之间的转换关系
对数据库模型依赖非常大,在软件需求变更频繁的系统中,会导致非常难以调整及维护。可能数据
库中随便改一个表或字段的定义,Java代码中要修改几十处。
很难定位问题,也很难进行性能优化:需要精通框架,对数据库模型设计也非常熟悉。
Mybatis的使用
- 首先创建一个Maven项目 mybatis-study,在pom.xml中引入SpringBoot及Mybatis需要的依赖包,
<?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>
<!-- 默认使用的Spring Framework版本为5.2.10.RELEASE -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>mybatis-study</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- spring-boot-starter-web: 基于SpringBoot开发的依赖包,
会再次依赖spring-framework中基本依赖包,aop相关依赖包,web相关依赖包,
还会引入其他如json,tomcat,validation等依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除tomcat依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加 Undertow 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- mybatis-spring-boot-starter: Mybatis框架在SpringBoot中集成的依赖包,
Mybatis是一种数据库对象关系映射Object-Relationl Mapping(ORM)框架,
其他还有如Hibernate等 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- Mybatis代码生成工具 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<!-- druid-spring-boot-starter: 阿里Druid数据库连接池,同样的运行时需要 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<!-- JDBC:mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
<scope>runtime</scope>
</dependency>
<!-- spring-boot-devtools: SpringBoot的热部署依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<!-- 不能被其它模块继承,如果多个子模块可以去掉 -->
<optional>true</optional>
</dependency>
<!-- lombok: 简化bean代码的框架 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- spring-boot-starter-test: SpringBoot测试框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- SpringBoot的maven打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 明确指定一些插件的版本,以免受到 maven 版本的影响 -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.3</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>
- 准备数据库
在根目录下创建一个dp包,然后创建一个init.sql的文件,然后放入数据的初始化语句
drop database if exists mybatis_study;
create database mybatis_study character set utf8mb4;
use mybatis_study;
drop table if exists user;
create table user(
id int primary key auto_increment,
username varchar(20) not null unique comment '账号',
password varchar(20) not null comment '密码',
nickname varchar(20) comment '用户昵称',
sex bit default 0 comment '性别,0/false为女,1/true为男',
birthday date comment '生日',
head varchar(50) comment '头像地址',
create_time timestamp default now() comment '创建日期,默认为插入时的日期'
) comment '用户表';
insert into user(username, password) values ('a1', '11');
insert into user(username, password) values ('a2', '12');
insert into user(username, password) values ('b', '2');
insert into user(username, password) values ('c', '3');
- 准备一个SpringBoot的启动类
在java目录创建org.example.Application的启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 准备SpringBoot的配置文件
在resource目录下创建一个application.properties文件,其中账号和密码为你自己MySQL的账号和密码
debug=true
# 设置打印日志的级别,及打印sql语句
#日志级别:trace,debug,info,warn,error
#基本日志
logging.level.root=INFO
#扫描的包并按debug日志级别打印:druid.sql.Statement类和org.example包
logging.level.druid.sql.Statement=DEBUG
logging.level.org.example=DEBUG
#数据库连接池配置:
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_study?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=******
#指定Mybatis表和实体映射关系xml配置文件,包含表与实体的映射,字段和属性的映射,及各个sql语句
mybatis.mapper-locations=classpath:mapper/**Mapper.xml
- 然后在对database进行配置,配置完成之后在init.sql页面点击右键run,然后就可以在database里面看到自己刚刚创建的数据库
6. 最后运行Spring启动类,不报即可
Mybatis开发
Java实体类
需要根据数据库表建立 Java类,表中的每个字段需要对应类中的属性。之后会在 Mybatis 的映射文件中配置字段与属性的映射关系。
这部分实体类对象,对应以前面图中绿色的两个部分,一般会以如下方式呈现:
- 作为传入数据,表现在方法参数上。
- 作为结果集转换的输出数据,表现在方法的返回值上
配置Mybatis数据操作Mapper接口
这部分对应以上图中淡黄色的部分:由开发人员提供执行SQL的接口,框架会自动为接口生成代理类,
代理类中会包含模版方法的代码逻辑
在 org.example.mapper 包下创建的用户类的 Mybatis 映射 Mapper 接口:
注意接口需要使用注解 @Mapper 及 @Component 。在SpringBoot启动后,SpringBoot会自动扫描到启
动类包下的注解类,且Mybatis框架会进一步完成生成代理类的工作。
@Mapper
@Component
public interface UserMapper {
User selectById(Integer id);
}
配置Mybatis实体映射文件
映射文件是xml文件,且在 application.properties 中指定了路径,是在classpath:mapper/**Mapper.xml ,该路径是在类加载路径下的mapper文件夹下,所有以Mapper.xml 结尾的文件。所以可以在 src/main/resources 下新建 mapper 文件夹,并创建文章类的映射文件UserMapper(这个名字最好和Mapper接口类中的UserMapper一致)
<?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="org.example.mapper.UserMapper">
<resultMap id="Basespace" type="org.example.model.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
</resultMap>
</mapper>
- mapper标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接口的全限定名,包括全包名.类名
- resultMap标签:配置查询结果集与 Java 类的映射关系,包括如下配置:
- id 绑定该映射的键,之后可以通过 id 值来使用。在本命名空间使用可以直接使用,其他命
名空间需要以 命名空间.resultMap的id 的方式来使用。之后的部分会进一步使用。这里先大
概介绍。 - type 绑定该结果集映射的 Java 类。
- id标签指定结果集的唯一标识,一般为数据库主键。
- result标签指定结果集字段与 Java 类中属性的映射,其中 column 指定结果集字段,
property 指定 Java 属性。
配置SQL
之后还需要在 Mybatis 映射文件中配置 SQL,需要配置在mapper>标签下,与<resultMap标签同级
对 CRUD 操作来说,每个不同类型的操作都有对应的标签
- select标签:查询语句
- insert标签:插入语句
- update标签:修改语句
- delete标签:删除语句
<select id="selectById" parameterType="java.lang.Integer"
resultMap="BaseResultMap">
select * from User where id=#{id}
</select>
注意:
- 都必须指定 id 属性,该属性会绑定 mapper 接口方法,值和方法名相同。本质上 Mybatis 是根据 mapper包名 查找对应的命名空间,之后在调用方法时,在该命名空间下根据 接口方法名 查找对应 id 的 sql。
- 使用 parameterType 指定传入数据的类型,该配置只能在mapper接口方法参数只有一个时使用,也可以省略。如果有多个方法参数,需要另行设置,
- .查询语句可以使用 resultMap 属性绑定结果集映射,值为结果集映射的 id 。注意返回结果集有一行和多行数据时,都可以使用 resultMap 绑定映射,对应接口方法的返回值是一个对象(结果集为一行),或 List<类型>(结果集为多行)
- 对插入,修改,删除这样的更新操作来说,返回的值都是 int,表示更新成功的数量,所以不用指定 resultMap 。
- 传入数据可以在 sql 语句中使用 #{方法参数名} 的方式获取。
单元测试
可以在Spring中方便的使用JUnit来完成单元测试,在src/test/java下,创建一个单元测试类//指定为Spring环境中的单元测试
@RunWith(SpringRunner.class)
//指定为SpringBoot环境的单元测试,Application为启动类
@SpringBootTest(classes = Application.class)
//使用事务,在SpringBoot的单元测试中会自动回滚
@Transactional
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void selectByIdTest(){
User user = userMapper.selectById(1);
System.out.println(user);
}
}
执行结果:
多个方法参数(模糊匹配)
当接收多个方法参数时,xml 映射文件中的 sql 配置不能再使用 parameterType 属性,需要在方法参
数上使用 @Param(“参数的名称”) ,之后在 sql 中使用 #{参数的名称} 的方式来替换占位符。
@Mapper//启动时会扫描该注解的接口,动态生成代理类
@Component
public interface UserMapper {
User selectById(Integer id);
int insert(User user);
List<User> selectLike(@Param("username") String username,@Param("password") String password);
}
User.xml映射文件的配置
<select id="selectLike" resultMap="BaseResultMap">
select * from user where
username like #{username} and password like #{password}
</select>
单元测试类1
例如这里模糊匹配username为“a”开头的,password为“1”开头的
@Test
public void selectLikeTest(){
String username = "a%";
String password = "1%";
List<User> users = userMapper.selectLike(username,password);
System.out.println(users);
}
运行结果
#{参数} vs ${参数}
例如上述示例,假如我们模糊查询出来的数据想让它进行降序排序,那么我们要怎么做呢?
对于 #{参数} 的使用来说,如果参数是字符串,在替换占位符时,会在 sql 语句中加上单引号。如果是不能使用单引号的字符串,例如 sql 语句是 order by 字段 {传入参数} ,此时 {传入参数} 就需要使用 ${传入参数} 这样的占位符,替换时不会带上单引号。
示例:在以上模糊查询语句中,加上根据文章标题排序的功能,要求是根据方法参数传入的字符串 asc 或 desc 来排序
- 首先将UserMapper接口方法调整为
@Mapper//启动时会扫描该注解的接口,动态生成代理类
@Component
public interface UserMapper {
User selectById(Integer id);
int insert(User user);
List<User> selectLike(@Param("username") String username,
@Param("password") String password,
@Param("orderBy") String orderBy);
}
- 然后再将UserMapper.xml调整为:
<select id="selectLike" resultMap="BaseResultMap">
select * from user where
username like #{username} and password like #{password}
order by password ${orderBy}
</select>
- 然后在调整单元测试代码
@Test
public void selectLikeTest(){
String username = "a%";
String password = "1%";
List<User> users = userMapper.selectLike(username,password,"desc");
System.out.println(users);
}
}
插入时获取自增主键
在之前插入数据时,如果是自增主键,插入后无法获取到。此时需要在 Mybatis 映射文件中,insert标签配置如下属性
- useGeneratedKeys:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
- keyColumn:设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
- keyProperty:指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或insert 语句的 selectKey 子元素设置它的值,默认值:未设置( unset )。如果生成列不止一个,可以用逗号分隔多个属性名称。
如:我们将插入的数据使用id进行自增
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into user(username,password,nickname,
sex,birthday,head
)values (
#{username},#{password},#{nickname},
#{sex},#{birthday},#{head}
)
</insert>
以上是关于了解MyBatis框架的主要内容,如果未能解决你的问题,请参考以下文章
Spring+SpringMVC+MyBatis+Maven框架整合