关注公众号“Java 后端技术全栈”**
回复“面试”获取全套大厂面试资料
前言
前面我们讲过 Spring Boot 集成 JPA,但是由于很多小伙伴的项目中用的并不是 JPA,用的是 Mybatis,并且我也调查过很多朋友,三个 ORM 框架使用比例大致为
Mybatis:JPA:Hibernate:其他=6:3:0.5:0.5
不接受反驳,因为没有多大意义。
面试题:Mybatis 和 Hibernate 的区别
这题目答案网上多得很,可以用漫天非来形容。但是我们这里会关注一个点不同点:sql 的优化。
由于 mybatis 的 sql 都是写在 xml 里,因此优化 sql 比 hibernate 方便很多。而 hibernate 的 sql 很多都是自动生成的,无法直接维护 sql;虽有 hql,但功能还是不及 sql 强大,见到报表等变态需求时,hql 也歇菜,也就是说 hql 是有局限的;hibernate 虽然也支持原生 sql,但开发模式上却与 orm 不同,需要转换思维,因此使用上不是非常方便。总之写 sql 的灵活度上 hibernate 不及 mybatis。其实在 Mybatis 中我们也可以使用注解的方式来操作数据库(注解中写 sql)。
xml 方式集成
MyBatis 是现如今最流行的 ORM 框架之一,我们先来了解一下什么是 ORM 框架。
ORM 框架
对象关系映射(Object Relational Mapping,ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM 是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
为什么需要 ORM?
当你开发一个应用程序的时候(不使用 O/R Mapping),可能会写不少数据访问层代码,用来从数据库保存、删除、读取对象信息等;在 DAL 中写了很多的方法来读取对象数据、改变状态对象等任务,而这些代码写起来总是重复的。针对这些问题 ORM 提供了解决方案,简化了将程序中的对象持久化到关系数据库中的操作。
ORM 框架的本质是简化编程中操作数据库的编码,在 Java 领域发展到现在基本上就剩两家最为流行,一个是宣称可以不用写一句 SQL 的 Hibernate,一个是以动态 SQL 见长的 MyBatis,两者各有特点。在企业级系统开发中可以根据需求灵活使用,会发现一个有趣的现象:传统企业大都喜欢使用 Hibernate,而互联网行业通常使用 MyBatis。
MyBatis 介绍
MyBatis 是一款标准的 ORM 框架,被广泛的应用于各企业开发中。MyBatis 最早是 Apache 的一个开源项目 iBatis,2010 年这个项目由 Apache Software Foundation 迁移到了 Google Code,并且改名为 MyBatis,2013 年 11 月又迁移到 Github。从 MyBatis 的迁移史,也可以看出源码托管平台的发展史,GitHub 目前已经成为世界上最大的开源软件托管平台,建议大家多多关注这个全球最大的同性社交网站。
MyBatis 支持普通的 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索封装。MaBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。
作为一款使用广泛的开源软件,它的特点有哪些呢?
优点
SQL 被统一提取出来,便于统一管理和优
SQL 和代码解耦,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰、更易维护、更易单元测试
提供映射标签,支持对象与数据库的 ORM 字段关系映射
提供对象关系映射标签,支持对象关系组件维护
灵活书写动态 SQL,支持各种条件来动态生成不同的 SQL
缺点
MyBatis 几个重要的概念
Mapper 配置可以使用基于 XML 的 Mapper 配置文件来实现,也可以使用基于 Java 注解的 MyBatis 注解来实现,甚至可以直接使用 MyBatis 提供的 API 来实现。
Mapper 接口是指自行定义的一个数据操作接口,类似于通常所说的 DAO 接口。早期的 Mapper 接口需要自定义去实现,现在 MyBatis 会自动为 Mapper 接口创建动态代理对象。Mapper 接口的方法通常与 Mapper 配置文件中的 select、insert、update、delete 等 XML 结点存在一一对应关系。
Executor,MyBatis 中所有的 Mapper 语句的执行都是通过 Executor 进行的,Executor 是 MyBatis 的一个核心接口。
SqlSession,是 MyBatis 的关键对象,是执行持久化操作的独享,类似于 JDBC 中的 Connection,SqlSession 对象完全包含以数据库为背景的所有执行 SQL 操作的方法,它的底层封装了 JDBC 连接,可以用 SqlSession 实例来直接执行被映射的 SQL 语句。
SqlSessionFactory,是 MyBatis 的关键对象,它是单个数据库映射关系经过编译后的内存镜像。SqlSessionFactory 对象的实例可以通过 SqlSessionFactoryBuilder 对象类获得,而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出。
MyBatis 的工作流程如下:
首先加载 Mapper 配置的 SQL 映射文件,或者是注解的相关 SQL 内容。
创建会话工厂,MyBatis 通过读取配置文件的信息来构造出会话工厂(SqlSessionFactory)。
创建会话。根据会话工厂,MyBatis 就可以通过它来创建会话对象(SqlSession),会话对象是一个接口,该接口中包含了对数据库操作的增、删、改、查方法。
创建执行器。因为会话对象本身不能直接操作数据库,所以它使用了一个叫做数据库执行器(Executor)的接口来帮它执行操作。
封装 SQL 对象。在这一步,执行器将待处理的 SQL 信息封装到一个对象中(MappedStatement),该对象包括 SQL 语句、输入参数映射信息(Java 简单类型、HashMap 或 POJO)和输出结果映射信息(Java 简单类型、HashMap 或 POJO)。
操作数据库。拥有了执行器和 SQL 信息封装对象就使用它们访问数据库了,最后再返回操作结果,结束流程。
在我们具体的使用过程中,就是按照上述的流程来执行。
什么是 MyBatis-Spring-Boot-Starter?
mybatis-spring-boot-starter 是 MyBatis 帮助我们快速集成 Spring Boot 提供的一个组件包,使用这个组件可以做到以下几点:
构建独立的应用
几乎可以零配置
需要很少的 XML 配置
mybatis-spring-boot-starter 依赖于 MyBatis-Spring 和 Spring Boot,最新版 1.3.2 需要 MyBatis-Spring 1.3 以上,Spring Boot 版本 1.5 以上。
注意 :mybatis-spring-boot-starter 是 MyBatis 官方开发的 Starter,而不是 Spring Boot 官方开发的启动包,其实是 MyBatis 看 Spring Boot 市场使用度非常高,因此主动开发出 Starter 包进行集成,但这一集成确实解决了很多问题,使用起来比以前简单很多。mybatis-spring-boot-starter 主要提供了两种解决方案,一种是简化后的 XML 配置版,一种是使用注解解决一切问题。
MyBatis 以前只有 XML 配置这种使用的形式,到了后来注解使用特别广泛,MyBatis 也顺应潮流提供了注解的支持,从这里可以看出 MyBatis 一直都跟随着主流技术的变化来完善自己。接下来给大家介绍一下如何使用 XML 版本。
XML 版本保持映射文件的方式,最新版的使用主要体现在不需要实现 Dao 的实现层,系统会自动根据方法名在映射文件中找到对应的 SQL。
初始化脚本
为了方便项目演示,需要在 test 仓库创建 users 表,脚本如下:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`userName` varchar(32) DEFAULT NULL COMMENT '用户名',
`passWord` varchar(32) DEFAULT NULL COMMENT '密码',
`user_sex` varchar(32) DEFAULT NULL,
`nick_name` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 初始化一条数据
INSERT INTO `my_jpa`.`users`(`id`, `userName`, `passWord`, `user_sex`, `nick_name`) VALUES (1, 'zhangsan', '123456', 'man', 'xiaosan');
复制代码
添加依赖包
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.4</version>
</dependency>
复制代码
application.properties 添加配置项
properties
#mysql配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/my_jpa?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=lwt123456@
#mybatis配置
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.tian.usercenter.entity
复制代码
实体类
package com.tian.usercenter.entity;
public class UserEntity {
private Integer id;
private String userName;
private String passWord;
private String userSex;
private String nickName;
//set get
}
复制代码
在创建一个 UserMapper.java
java
import com.tian.usercenter.entity.UserEntity;
import java.util.List;
public interface UserMapper {
List<UserEntity> getAll();
UserEntity getOne(Long id);
void insert(UserEntity user);
void update(UserEntity user);
void delete(Long id);
}
复制代码
在 resources 目录下添加 mybatis 目录
1.在该目录下添加 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>
<settings>
<setting name="callSettersOnNulls" value="true"/>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
<typeAliases>
<typeAlias alias="Integer" type="java.lang.Integer" />
<typeAlias alias="Long" type="java.lang.Long" />
<typeAlias alias="HashMap" type="java.util.HashMap" />
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
<typeAlias alias="ArrayList" type="java.util.ArrayList" />
<typeAlias alias="LinkedList" type="java.util.LinkedList" />
</typeAliases>
</configuration>
复制代码
2.在本目录下添加 mapper 目录,然后再 mapper 里添加 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="com.tian.usercenter.dao.UserMapper" >
<resultMap id="BaseResultMap" type="com.tian.usercenter.entity.UserEntity" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="userName" property="userName" jdbcType="VARCHAR" />
<result column="passWord" property="passWord" jdbcType="VARCHAR" />
<result column="user_sex" property="userSex" jdbcType="VARCHAR"/>
<result column="nick_name" property="nickName" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
id, userName, passWord, user_sex, nick_name
</sql>
<select id="getAll" resultMap="BaseResultMap" >
SELECT
<include refid="Base_Column_List" />
FROM users
</select>
<select id="getOne" parameterType="java.lang.Integer" resultMap="BaseResultMap" >
SELECT
<include refid="Base_Column_List" />
FROM users
WHERE id = #{id}
</select>
<insert id="insert" parameterType="com.tian.usercenter.entity.UserEntity" >
INSERT INTO users (userName,passWord,user_sex)
VALUES (#{userName}, #{passWord}, #{userSex})
</insert>
<update id="update" parameterType="com.tian.usercenter.entity.UserEntity" >
UPDATE users SET
<if test="userName != null">userName = #{userName},</if>
<if test="passWord != null">passWord = #{passWord},</if>
nick_name = #{nickName}
WHERE id = #{id}
</update>
<delete id="delete" parameterType="java.lang.Integer" >
DELETE FROM users WHERE id =#{id}
</delete>
</mapper>
复制代码
启动类添加注解
@MapperScan("com.tian.usercenter.dao")扫描的**Mapper.java 目录
@SpringBootApplication
@MapperScan("com.tian.usercenter.dao")
public class UserCenterApplication {
public static void main(String[] args) {
SpringApplication.run(UserCenterApplication.class, args);
}
}
复制代码
使用(这里只是为了演示,所以 controller 就直接掉 mapper 了,具体开发中按照项目规范来)
@RestController
public class MybatisController {
@Resource
private UserMapper userMapper;
@GetMapping("/mybatis")
public Object mybatis(){
List<UserEntity> userEntityList = userMapper.getAll();
return userEntityList;
}
}
复制代码
启动项目,请求地址:http://localhost:8080/mybatis
OK,自此,xml 方式的 Springboot 集成 Mybatis 就搞定了。下面继续搞注解方式:
注解方式集成
application.properties 文件中的配置得删除掉 xml 相关的
#mybatis.config-location=classpath:mybatis/mybatis-config.xml
#mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.tian.usercenter.entity
复制代码
UserMapper.java 修改
import com.tian.usercenter.entity.UserEntity;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Select("select * from users")
List<UserEntity> getAll();
@Select("select * from users where id= #{id}")
UserEntity getOne(@Param("id") Long id);
@Insert("insert into users (id,userName,passWord,user_sex,nick_name) values (#{id},#{userName}{,#{passWord},#{userSex},#{nickName})")
void insert(UserEntity user);
@Update("update users set username=#{userName} where userName=#{userName}")
void update(UserEntity user);
@Delete("delete from users where id=#{id}")
void delete(@Param("id") Long id);
}
复制代码
UserMapper.xml 文件删掉。重启项目;
请求:http://localhost:8080/mybatis
认真的朋友看到了上面的返回结果中有两个字段 userSex 和 nickName 为 Null。但是在 xml 方式中是正常返回的。
这里可以使用添加一个配置项来解决下换线与驼峰的问题
mybatis.configuration.map-underscore-to-camel-case=true
复制代码
最后结果为:
好了,上面两种方式都成功实现,今天就分享到此。
码字不易,希望你 点个在看+分享,谢谢啦!
推荐阅读
扔掉 Postman 吧,试试 Postwoman 高能神器!
Idea 公司真牛逼,发行适合程序员编程字体
评论