一、MyBatis简介
放一个官方的解释
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
以我的角度用简单的话来说
一个持久层框架,封装大多数的 JDBC 样板代码,使得开发者只需关注 SQL 本身,而不需要花费精力去处理例如注册驱动,创建 Connection,以及确保关闭 Connection 这样繁杂的代码。通过写xml文件或者注解将Java的POJO映射成数据库中的记录
好像人家写的也很好理解,哈哈哈哈~!
下面这个是Mybatis的logo,带着红色眼罩的小胖鸟忍者
原来的名字叫iBais
本来代码在Apache放着,后来又放到Google Code上了。然后就改名为Mybatis了~
优点
很容易学,很小巧,没有第三方依赖,装两个jar包+几个sql映射文件即可
灵活,因为我是学完动态sql之后才回来写的笔记,月学到后面越发现这玩意是真灵活能有很多组合呀,判断啊。然后呢,sql写在xml文件里,能方便的进行统一管理和优化。
提供映射标签,支持对象与数据库的字段关系映射
提供xml标签,支持动态sql就是编写一些判断语句根据实时发生的情况进行改变这就叫动态
缺点
写sql 的时候工作量很大,对于很多字段的,关联了很多表的更是这样,学着学着我就有感觉这玩意也没多容易啊不想前面学的spring和springMVC这么简单,这还是要写这么多。
sql语句依赖于数据库,移植性差
二级缓冲机制不太行
二、 入门案例
2.1 安装Mybatis
我们通过Maven来解决资源包问题
分别有mysql,mybatis,junit
后面我又放了个插件,防止注册的时候把xml文件打不进去(后面会用到)
<?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> <groupId>com.caq</groupId> <artifactId>Mybatis</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.16</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> </dependency> </dependencies> <build> <!-- 项目打包时会将java目录中的*.xml文件也进行打包 --> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project>
2.2 通过xml构建SqlSessionFactory
通过xml构建SqlSessionFactory
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
以下是mybatis-config.xml和jdbc.properties配置
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
所以先写个xml配置文件来配置SqlSessionFactory
实验环境如下:
Idea2019.3
mysql5.X
mybatis5.X
Maven3.8
目录结构如下
jdbc.driver=com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=root
mybatis可以使用properties来引入外部properties配置文件的内容
resource:引入类路径下的资源
url:引入网络路径或磁盘路径下资源
我们通过引入外部配置文件的方式来配置全局配置文件,进一步解耦方便维护~
<?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> <properties resource="dbconfig.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 取出配置文件中的值用的是${}的形式--> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> </configuration>
2.3 从 SqlSessionFactory 中获取 SqlSession
获取sqlSession的实例,能直接执行已经映射的sql语句
SqlSession openSession = sqlSessionFactory.openSession();
顾名思义(从名称想到所包含的意义,给用心的我点个大大的赞!),不在详细解释标题啥意思了~
Mybatis执行流程:
根据xml文件(全局配置文件)创建一个SqlSessionFactory对象里面有数据源和一些运行环境信息
sql映射文件,配置了每一个sql,以及sql的封装规则等。
将sql映射文件注册在全局配置文件中
写代码
根据全局配置文件得到sqlSessionFactory
使用sqlSession工厂,获取到sqlSession对象使用它来执行CRUD
一个sqlSession就是代表和数据库的一次会话,用完关闭
使用sql的唯一标志来告诉Mybatis执行那个sql。sql都是保存在sql映射文件里的
2.4 探究已映射的 SQL 语句
既然要映射sql语句我们先要创建对应的数据库
和对应数据库字段的的实体类
@Alias这个注解是给这个实体类起的别名叫emp
通过这个实体类来映射数据库中的一条记录,一个对象就是数据库中的一条记录~
package com.caq.mybatis.bean; import org.apache.ibatis.type.Alias; @Alias("emp") public class Employee { private Integer id; private String lastName; private String email; private String gender; private Department dept; public Employee() { } public Employee(Integer id, String lastName, String email, String gender, Department dept) { this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; this.dept = dept; } public Department getDept() { return dept; } public void setDept(Department dept) { this.dept = dept; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Employee{" + "id=" + id + ", lastName='" + lastName + '\'' + ", email='" + email + '\'' + ", gender='" + gender + '\'' + '}'; } }
下面这个就是sql映射文件
namespace就是命名空间;指定为接口的全类名
id就是唯一标识
resultType就是返回值类型,比如我们想返回的是员工的信息,那我们就返回Employee的全类名
#{id}:从传递过来的参数中取出id值
id指定接口中的方法,这样不仅文件和接口绑定,select标签也和方法进行了绑定
以上几点都是重点!!!画黑板了,记到本子上!
映射文件
<?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.caq.mybatis.dao.EmployeeMapper"> <!--什么意思呢?就是select这个标签是EmployeeMapper接口下getEmpById方法的实现--> <select id="getEmpById" resultType="emp"> select * from tbl_employee where id = #{id} </select> </mapper>
将我们写好的sql映射文件一定要注册到全局配置文件中
<mappers> <!-- <mapper resource="EmployeeMapper.xml"/>--> <!-- <mapper class="com.caq.mybatis.dao.EmployeeMapperAnnotation"/>--> <!-- 批量注册--> <package name="com.caq.mybatis.dao"/> </mappers>
测试效果
@Test public void test01() throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try { EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); System.out.println(employee); } finally { openSession.close(); } }
结果如下:
Employee{id=1, lastName=‘tom’, email=‘tom@caq.com’, gender=‘0’}
2.5 注解开发
面向接口编程
什么是面向接口编程?
面向接口编程是先把客户的业务逻辑线提取出来,作为接口,业务具体实现通过该接口的实现类来完成。当客户需求变化时,只需编写该业务逻辑的新的实现类,通过更改配置文件中该接口的实现类就可以完成需求,不需要改写现有代码,减少对系统的影响。(这个概念的理解很重要,先记着后面实践的时候会越来越清晰!)
这里我结合后面springboot的一些方式,释放了mybatis-config.xml文件,通过yml文件中的指定来替换。数据库映射mapper.xml文件通过在接口上写@Mapper注解和方法上写注解的方式实现
如下:
yml文件
mybatis: # 通过yml配置文件的方式解放了mybatis-config.xml文件 configuration: map-underscore-to-camel-case: true #开启驼峰命名
Mapper接口
package com.caq.admin.mapper; import com.caq.admin.bean.Account; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; //通过写@Mapper注解的方式释放了写mapper.xml映射文件的方式 @Mapper public interface AccountMapper { @Select("select * from account where id = #{id}") Account test(Long id); }
service层
package com.caq.admin.service;import com.caq.admin.bean.Account;import com.caq.admin.mapper.AccountMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class AccountService { @Autowired AccountMapper accountMapper; public Account getAcc(Long id){ return accountMapper.test(id); }}
controller层
@Controller@Slf4jpublic class IndexController { @Autowired AccountService accountService; @ResponseBody @GetMapping("/account") public Account getAccount(@RequestParam("id") Long id){ return accountService.getAcc(id); }}
测试
三、MyBatis-全局配置文件
配置文件很重要,下面我们来看看配置文件中的参数都是什么意思!
配置文档的顶层结构如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
3.1 属性(properties)
mybatis可以使用properties来引入外部properties配置文件的内容
resource:引入类路径下的资源
url:引入网络路径或磁盘路径下资源
<properties resource="dbconfig.properties"></properties>
设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 取出配置文件中的值用的是${}的形式--> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments>
前面的例子我们用的也是这种方式,写一个配置文件在外部,之后我们在全局配置文件中通过properties引入配置文件,之后通过${}来取配置文件中的值
3.2 设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
这几个 是很重要的点,所以特地提出来
设置名 描述 有效值 默认值
cacheEnabled 该配置影响所有映射器中配置的缓存的全局开关 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false
useColumnLabel 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 true | false true
defaultStatementTimeout 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 任意正整数 未设置 (null)
mapUnderscoreToCamelCase 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 true | false False
驼峰命名的开启很重要,因为在数据库中的字段两个字母组成的意思的时候往往通过下划线(_)分割,但在java中都是驼峰型的。为了解决这个问题,可以开启mapUnderscoreToCamelCase 来进行数据库字段和java属性的映射。下面会有演示
settings包含很多重要的设置项
setting用来设置每一个设置项
name设置项名
value设置项取值
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
第一个我们开启了驼峰映射,第二个是延迟加载后面我们会说
我们来看看是怎么映射的
@Alias("emp")public class Employee { private Integer id; private String lastName; }
我们的实体类Employee这个字段名是lastName
数据库中的这个字段是last_name
开启后,会自动把last_name映射为lastName所以查询的话是能查询成功的
这个是sql映射文件(接口式编程,我们要先在接口中定义getEmpById方法,参数设置为id)
<!-- id指定接口中的方法,这样不仅文件和接口绑定,select标签也和方法进行了绑定 什么意思呢?就是select这个标签是EmployeeMapper接口下getEmpById方法的实现 --> <select id="getEmpById" resultType="emp"> select * from tbl_employee where id = #{id} </select>
测试
// 接口式编程,方便解耦 @Test public void test01() throws IOException { // 1、获取sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 2、获取sqlSession对象 SqlSession openSession = sqlSessionFactory.openSession(); try { // 3、获取接口的实现类对象 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); // 第二种方式是先获取接口的实现类对象,之后实现接口的方法传入参数 Employee employee = mapper.getEmpById(1); System.out.println(employee); } finally { openSession.close(); } }
Employee{id=1, lastName=‘tom’, email=‘tom@caq.com’, gender=‘0’}
可以看到lastName是有值的
如果关闭驼峰,lastName这列是不显示值的如下
<settings> <setting name="mapUnderscoreToCamelCase" value="false"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
中间的步骤一样不在赘述,结果为:
Employee{id=1, lastName=NULL, email=‘tom@caq.com’, gender=‘0’}
3.3 类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
typeAliases:别名处理器,可以为我们的java类型起别名
别名不区分大小写
typeAliases为某个java类型起别名
type:指定要起别名的类型全类名;默认别名就是类名小写;employee
alias:指定新的别名
package:为某个包下的所有类批量起别名
name:指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写))
<typeAliases> <typeAlias type="com.caq.mybatis.bean.Employee" alias="emp"></typeAlias> </typeAliases> <!--批量别名--> <typeAliases> <package name="com.caq.mybatis.bean"/> </typeAliases>
批量起别名的情况下我们不想用默认的话,可以使用@Alias注解为某个类型指定新的别名
是吧,我们在Employee实体类上面加了个@Alias给它起了个别名叫emp
@Alias("emp") public class Employee {}
但是呢,虽然有别名,为了项目更好的维护我们一般都使用全类名。要不然谁知道你写的别名是啥意思
3.4 类型处理器(typeHandlers)
无论是MyBatis在预处理语句(PreparedStatement )中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成Java类型。
3.5 plugins插件
插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行
3.6 environments环境
尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:
每个数据库对应一个 SqlSessionFactory 实例
MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
每种环境使用一个environment标签进行配置并指定唯一标识符
可以通过environments标签中的default属性指定
一个环境的标识符来快速的切换环境
id:指定当前环境的唯一标识
transactionManager、和dataSource都必须有
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 取出配置文件中的值用的是${}的形式--> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment></environments>
这个就很好理解了,一些环境和配置信息~
3.7 dataSource
有这些类型: UNPOOLED | POOLED | JNDI | 自定义
UNPOOLED:不使用连接池,UnpooledDataSourceFactory
POOLED:使用连接池, PooledDataSourceFactory
JNDI: 在EJB 或应用服务器这类容器中查找指定的数据源
自定义:实现DataSourceFactory接口,定义数据源的获取方式。
• 实际开发中我们使用Spring管理数据源,并进行事务控制的配置来覆盖上述配置
3.8 mapper映射
重头戏它来了
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。
我们通过在全局配置文件进行注册
<mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper url="file:///var/mappers/AuthorMapper.xml"/> <mapper class="org.mybatis.builder.AuthorMapper"/></mappers>
这种方式有待提高,比较麻烦写一个注册一个。我们可以通过批量注册!
• 这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下
<!-- 将我们写好的sql映射文件一定要注册到全局配置文件中--> <mappers> <!-- <mapper resource="EmployeeMapper.xml"/



