最全面的Mybatis教程,从“开局”到“通关”,使用Mybatis实现CRUD,Mybatis配置文件,Mybatis日志配置,resultMap详解
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情
前言

本文将为大家对SSM框架 【Mybatis】 相关知识进行介绍,MyBatis 是一款优秀的半自动的ORM持久层框架,下边具体将对Mybatis的简介、Mybatis的CRUD实现,Mybatis的配置文件,Mybatis的日志配置,resultMap详解,分页实现,注解式开发,Lombok的使用,关联映射,动态SQL,Mybatis缓存等相关内容进行详尽介绍~
🚩 Are you ready❓ Let’s Go ❗️
👉Java全栈学习路线可参考: 【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考: 算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
目录一、Mybatis简介1️⃣什么是MybatisMyBatis 本是apache的一个开源项目【iBatis】;2010年这个项目由apache software foundation(Apache软件基金会) 迁移到了google code(谷歌的代码托管平台),并且改名为MyBatis;2013年11月迁移到Github。MyBatis是一款优秀的持久层框架MyBatis支持定制SQL、存储过程以及高级映射Mybatis避免了几乎所有的JDBC代码和手动设置参数,以及获取结果集Mybatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java的POJO(Plain Old Java Objects,普通老式Java对象)为数据库中的记录
Mybatis的Maven仓库下载地址: mvnrepository.com/artifact/or…Mybatis的GitHub地址: github.com/mybatis/myb…Mybatis的中文文档地址: mybatis.org/mybatis-3/z…
2️⃣持久化
持久化是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存)。
程序产生的数据首先都是在内存。内存是不可靠的,他丫的一断电数据就没了。那可靠的存储地方是哪里?硬盘、U盘、光盘等。我们的程序在运行时说的持久化通常就是指将内存的数据存在硬盘。3️⃣持久层
对于分层的概念我们知道:
业务是需要操作数据的数据是在磁盘上的具体业务调用具体的数据库操作,耦合度太高,复用性太差将操作数据库的代码统一抽离出来,自然就形成了介于业务层和数据库中间的独立的层
持久层的工作:
完成持久化工作的代码块层之间的界限非常明显4️⃣聊聊ORM
ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。
jpa(Java Persistence API)是java持久化规范,是orm框架的标准,主流orm框架都实现了这个标准。hibernate: 全自动的框架,强大、复杂、笨重、学习成本较高,不够灵活,实现了jpa规范。Java Persistence API(Java 持久层 API)MyBatis: 半自动的框架(懂数据库的人 才能操作) 必须要自己写sql,不是依照的jpa规范实现的。
很多人青睐 MyBatis ,原因是其提供了便利的 SQL 操作,自由度高,封装性好…… JPA对复杂 SQL 的支持不好,没有实体关联的两个表要做 join 的确要花不少功夫。
5️⃣MyBatis的优点和缺点
sql语句与代码分离,存放于xml配置文件中:
优点:便于维护管理,不用在java代码中找这些语句;缺点:JDBC方式可以用打断点的方式调试,但是MyBatis调试比较复杂,一般要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。
用逻辑标签控制动态SQL的拼接:
优点:用标签代替编写逻辑代码;缺点:拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。不要使用变通的手段来应对这种复杂的语句。
查询的结果集与java对象自动映射:
优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。缺点:对开发人员所写的SQL依赖很强。
编写原生SQL:
优点:接近JDBC,比较灵活。缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如MySQL数据库编程Oracle数据库,部分的SQL语句需要调整。
最重要的一点,使用的人多!公司需要!
二、第一个MyBatis程序
实现步骤:搭建环境—>导入MyBatis—>编写相关代码—>测试
1️⃣搭建环境
🍀(1)搭建数据库
— 创建数据库 create database `mybatis`; use mybatis; — 创建表 create table `user`( `id` int(20) not null, `name` varchar(30) default null, `pwd` varchar(30) default null, primary key(`id`) )engine=InnoDB default charset=utf8mb4; — 插入数据 insert into `user`(`id`,`name`,`pwd`) values (1,’张三’,’123′), (2,’李四’,’123′), (3,’王五’,’123′);复制代码
🍀(2)新建一个普通maven项目作为父项目,并导入sql驱动,mybatis,junit组件
mysql mysql-connector-java 5.1.46 org.mybatis mybatis 3.5.2 junit junit 4.12 复制代码
🍀(3)新建一个新组件作为子级项目,普通maven的module
🍀(4)添加配置文件
在src->main->resources目录下新建mybatis-config.xml文件,把官方的配置代码复制粘贴(不能在配置文件中写中文注释)配置文件的作用就是连接数据库 //数据库驱动,不同驱动可连接不同数据库服务器 //连接数据库的目录 //数据库名字,默认root //数据库密码,自己的数据库密码,一般为root 复制代码2️⃣编写mybatis工具类
MybatisUtils.java:
//SqlSessionFactory –生产–> SqlSession 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 //SqlSession完全包含了面向对象数据库执行SQL命令所需的方法 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession();} }复制代码3️⃣编写相关代码
🍀(1)实体类
public class User { private int id; private String name; private String pwd; public User() { } public User(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return “User{” + “id=” + id + “, name='” + name + ‘\” + “, pwd='” + pwd + ‘\” + ‘}’; } }复制代码
🍀(2)Dao接口
public interface UserDao { List getUserList(); }复制代码
🍀(3)xxxMapper.xml配置文件
接口的实现类要改为以xxxMapper.xml的配置文件注意事项:配置文件中不要写中文注释,如果非要写,解决方法见后面的异常解决方案 select * from mybatis.user where id = #{id} 复制代码
每一个Mapper.xml文件都需要在src->main->resources目录下的mybatis-config.xml核心配置文件中注册:
复制代码4️⃣测试 public class UserDaoTest { @Test public void test(){ //获取SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //获取mapper UserDao mapper = sqlSession.getMapper(UserDao.class); List list = mapper.getUserList(); for (User u:list){ System.out.println(u); } //不推荐使用以下方式 /* 这种方式能够正常工作,对使用旧版本 MyBatis 的用户来说也比较熟悉。但现在有了一种更简洁的方 式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加 类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。 */ // List list = sqlSession.selectList(“com.qian.dao.UserDao.getUserList”); // for (User user : list) { // System.out.println(user); // } //关闭SqlSession sqlSession.close(); } }复制代码三、使用Mybatis实现CRUD1️⃣Mapper接口public interface UserMapper { //查询全部用户 List getUserList(); //根据id查询用户 User getUserById(int id); //增加新的用户 boolean insertNewUser(User u); //删除用户 boolean deleteUserById(int id); boolean deleteUserByName(String name); //修改用户 boolean updateUserById(User u);}复制代码2️⃣xxxMapper.xml文件 select * from mybatis.user select * from mybatis.user where id=#{id} insert into mybatis.user (id, name, pwd) VALUES (#{id},#{name},#{pwd}) delete from mybatis.user where id=#{id} delete from mybatis.user where name=#{name} update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id} 复制代码3️⃣测试类public class UserDaoTest { @Test public void test(){ //获取SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); try{ //获取mapper UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 查询全表 List list = mapper.getUserList(); for (User u:list){ System.out.println(u); } //根据id查询 User user = mapper.getUserById(1); System.out.println(user); //插入新用户,注意:更新,插入,删除都需要提交事务 User user1 = new User(4,”李四”,”25615″); boolean isInserted = mapper.insertNewUser(user1); sqlSession.commit(); //代码优化 if (mapper.insertNewUser(new User(4,”李四”,”25615″))) sqlSession.commit(); //删除用户 if (mapper.deleteUserById(4))sqlSession.commit(); if (mapper.deleteUserByName(“李四”))sqlSession.commit(); //修改用户 if (mapper.updateUserById(new User(4,”王五”,”6849816″)))sqlSession.commit(); }finally { //关闭SqlSession sqlSession.close(); } }}复制代码4️⃣Map的使用
map可以代替任何的实体类,所以当我们数据比较复杂时,可以适当考虑使用map来完成相关工作。🍀(1)写方法
UserMapper.java:
User getUser(Map map); boolean addUser(Map map);复制代码
🍀(2)写sql
UserMapper.xml:
select * from mybatis.user where id=#{userId} insert into mybatis.user (id, name, pwd) VALUES (#{userId},#{userName},#{password}) 复制代码
🍀(3)测试
Test.java:
@Test public void test(){ //获取SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map map = new HashMap(); map.put(“userId”,5); User user = mapper.getUser(map); System.out.println(user); map.put(“userId”,5); map.put(“userName”,”孙悟空”); map.put(“password”,”123456″); if (mapper.addUser(map)) sqlSession.commit(); sqlSession.close(); }复制代码5️⃣模糊查询
🍀方案一:在Java代码中拼串
Test.java:
string name = “%IT%”;list names = mapper.getUserByName(name);复制代码
UserMapper.xml:
select * from user where name like #{name}复制代码
🍀方案二:在配置文件中拼接1
Test.java:
string name = “IT”;list users = mapper.getUserByName(name);复制代码
UserMapper.xml:
select * from user where name like “%”#{name}”%”复制代码
🍀方案三:在配置文件中拼接2
Test.java:
string name = “IT”;list users = mapper.getUserByName(name);复制代码
UserMapper.xml:
select * from user where name like “%${name}%”复制代码四、Mybatis配置文件1️⃣ 核心配置文件
核心配置文件mybatis-config.xml包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文件的层次结构如下(顺序不能乱):
1.properties是一个配置属性的元素2.settings设置,mybatis最为复杂的配置也是最重要的,会改变mybatis运行时候的行为3.typeAliases别名(在TypeAliasRegistry中可以看到mybatis提供了许多的系统别名)4.typeHandlers 类型处理器(比如在预处理语句中设置一个参数或者从结果集中获取一个参数时候,都会用到类型处理器,在TypeHandlerRegistry中定义了很多的类型处理器)5.objectFactory 对象工厂(myabtis在构建一个结果返回的时候,会使用一个ObjectFactory去构建pojo)6.plugins 插件7.environments 环境变量 environment 环境变量 transactionManager 事务管理器 dataSource 数据源 databaseIdProvider 数据库厂商标识8.mappers 映射器复制代码
下面针对几个重要的元素environments,properties,mappers,typeAliases,settings进行讲解。
2️⃣environments(环境)
environments可以为mybatis配置多环境运行,将SQL映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过default指定),如果想切换环境修改default的值即可。
最常见的就是,生产环境和开发环境,两个环境切换必将导致数据库的切换。
复制代码dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。数据源是必须配置的。有三种内建的数据源类型:type=”[UNPOOLED|POOLED|JNDI]”) – unpooled:这个数据源的实现只是每次被请求时打开和关闭连接。 – pooled:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。 – jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。复制代码数据源也有很多第三方的实现,比如druid,hikari,dbcp,c3p0等等….具体的一套环境,通过设置id进行区别,id保证唯一!子元素节点:transactionManager – [ 事务管理器 ](以下两种事务管理器类型都不需要设置任何属性)复制代码子元素节点:数据源(dataSource)3️⃣properties(属性)
数据库连接信息我们最好放在一个单独的文件中。
🍀(1)在资源目录下新建一个db.properties
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/ssm?useSSL=true&useUnicode=true&characterEncoding=utf8username=rootpassword=root复制代码
🍀(2)将db.properties文件导入核心配置文件
复制代码4️⃣mappers(映射器)
mappers的存在就是要对写好的mapper和xml进行统一管理,要不然系统怎么知道我们写了哪些mapper。
🍀(1)常用引入方式
复制代码
🍀(2)在Mapper文件里进行绑定
复制代码
namespace中文意思:命名空间,作用是namespace的命名必须跟某个接口同名,这才能找到实现绑定。
5️⃣typeAliases(类型别名)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
在mybatis-config.xml -> configuration进行配置:
复制代码配置以后xxxMapper.xml的返回值(resultType)就可以替换为resultType user实体类较少的时候使用第一种,较多就直接扫描包目录第二种也可以用注解@Alias(“xxx”)给类起别名6️⃣settings(设置)
settings能对我的一些核心功能进行配置,如懒加载、日志实现、缓存开启关闭等。
简单参数说明:
参数描述有效值默认值cacheEnabled该配置影响的所有映射器中配置的缓存的全局开关。true /falsetruelazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。true / falsefalseuseColumnLabel使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。true / falsetrueuseGeneratedKeys允许 JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。true / falseFalsedefaultStatementTimeout设置超时时间,它决定驱动等待数据库响应的秒数。Any positive integerNot Set (null)mapUnderscoreToCamelCase是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。true / falseFalselogPrefix指定 MyBatis 增加到日志名称的前缀。Any StringNot setlogImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J / LOG4J / LOG4J2 / JDK_LOGGING / COMMONS_LOGGING / STDOUT_LOGGING / NO_LOGGINGNot set
完整的 settings 元素,有很多可以配置的选项(可以自行了解):
复制代码五、Mybatis日志配置
配置日志的一个重要原因是想在调试的时候能观察到sql语句的输出,能查看中间过程
1️⃣标准日志实现
指定 MyBatis 应该使用哪个日志记录实现。如果此设置不存在,则会自动发现日志记录实现。STDOUT_LOGGING:标准输出日志。
… … 复制代码2️⃣组合logback完成日志功能
🍀(1)导入log4j的包
ch.qos.logback logback-classic ${logback.version}复制代码
🍀(2)log4j.properties配置文件
System.out ${pattern} ${pattern} ${log_dir}/sql.log 复制代码
🍀(3)setting设置日志实现
复制代码六、resultMap详解
如果数据库字段和实体的字段是一一对应,那么MyBatis会【自动映射】,但是如果不一致,比如一个叫user一个叫username,那么就需要我们手动的建立一一映射的关系了。
🍀(1)Java实体类
public class User { private int id; //id private String name; //姓名,数据库为username private String password; //密码,一致 //构造 //set/get //toString()}复制代码
🍀(2)mapper接口
//根据id查询用户User selectUserById(int id);复制代码
🍀(3)mapper映射文件
select * from user where id = #{id}复制代码
🍀(4)测试与结果分析
Test.java:
@Testpublic void testSelectUserById() { UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.selectUserById(1); System.out.println(user); session.close();}复制代码
结果:
User{id=1, name=’null’, password=’123′}复制代码
查询出来发现 name为空 . 说明出现了问题!
分析:
select * from user where id = #{id} 可以看做select id,username,password from user where id = #{id}mybatis会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) , 利用反射去对应的实体类中查找相应列名的set方法设值,当然找不到username
解决方案:
方案一:为列名指定别名 , 别名和java实体类的属性名一致 。
select id , username as name ,password from user where id = #{id}复制代码
方案二:使用结果集映射->ResultMap 【推荐】
select id , username , password from user where id = #{id}复制代码
结论:
这个地方我们手动调整了映射关系,称之为【手动映射】。但如果不调整呢? MyBatis当然会按照约定自动映射。当然约定的最基本的操作就是全部都一样,还有就是下划线和驼峰命名的自动转化。
复制代码后记
本文呢为大家对SSM框架 【Mybatis】 相关知识进行了介绍,MyBatis 是一款优秀的半自动的ORM持久层框架,本文具体对Mybatis的简介、Mybatis的CRUD实现,Mybatis的配置文件,Mybatis的日志配置,resultMap详解相关内容 进行了详细介绍,下期将继续对分页实现,注解式开发,Lombok的使用,关联映射,动态SQL,Mybatis缓存等相关内容进行详尽介绍~
希望本文的分享能够使你有所收获,如果你想继续深入的学习数据结构与算法相关的知识,或想继续深入的学习Java相关的知识与技术,可以参考:
👉Java全栈学习路线可参考: 【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考: 算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~