简介
查看Mybatis官方文档:https://mybatis.org/mybatis-3/zh/index.html
- Mybatis是一款优秀的持久层框架,它支持
自定义SQL
,存储过程
以及高级映射
。 - Mybatis
免除了
几乎所有的JDBC代码
以及设置参数
和获取结果集
的工作。 - Mybatis可以通过简单的
XML
或者注解
来配置和映射原始类型
,接口
和java POJO
为数据库中的记录。
Mybatis SQL 映射框架使得一个面向对象构建的应用程序
去访问一个关系型数据库
变得更容易。
MyBatis使用XML描述符
或注解
将对象
与存储过程
或SQL
语句耦合。
Mybatis整体架构
接口层:SqlSession就是我们与myabtis完成交互的核心接口。
核心层:SqlSession执行的方法,底层需要经过配置文件的解析,SQL解析,请求参数映射,结果集映射的支持。
支持层:核心层的功能实现,是基于底层的各个模块,共同协同完成。
Mybatis与Hibernate比对
简单使用-基于Mapper动态代理
注意点:
- mapper.xml文件中的namespace属性配置一定要和Mapper(定义的Dao接口)接口的全限定名相同。
- mapper.xml文件中定义的元素statement,它们的id属性要和Mapper(定义的Dao接口)接口的方法名相同。
- Mapper(定义的Dao接口)接口方法的方法
参数
类型,mapper.xml
中定义的元素statement
的parameterType
属性中声明的类型一致。 - Mapper(定义的Dao接口)接口方法的方法
返回值
类型,mapper.xml
中定义的元素statement
的resultType
属性中声明的类型一致。
项目引入mybatis依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>
定义Mybatis配置文件
<?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>
<!-- 定义全局参数 -->
</settings>
<environments default="dataSourceInfo">
<environment id="dataSourceInfo">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/userInfo.xml"/>
</mappers>
</configuration>
定义Mapper接口
public interface UserInfoMapper {
UserInfo findById();
}
实体类
public class UserInfo {
private String id;
private String name;
private String sex;
// getter setter toString equals hashcode
}
mapper.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.test.mybatis.mapper.UserInfoMapper">
<select id="findById" resultType="com.test.mybatis.entity.UserInfo">
select * from user_info where id = #{id}
</select>
</mapper>
测试运行
public static void main(String[] args) throws Exception {
InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取Mapper接口的代理
UserInfoMapper mapper = sqlSession.getMapper(UserInfoMapper.class);
UserInfo userData= mapper .findById("123456");
System.out.println(userData);
}
一对一,多对一配置
如果存在关联查询,那么在mapper.xml中,可以配置<resultMap>
标签属性。将数据库中的表字段与对象中的属性字段做映射。将mapper.xml中对应方法的返回属性resultType
替换为resultMap
,引用配置的resultMap
。
一对一
使用一对一查询时,在一个实体类中添加另一实体类属性。用resultMap
实现映射关系时,使用association
连接,javaType
为封装的类型。
<!--
一对一查询
<association 解决一对一问题
property="student" 对应Score 中 student属性
column="studentid" 对应Score_tb 与 student_tb关联的外键 列名,可以不写
javaType="Student" 将其他非Score 中的字段写入Student 类
-->
<resultMap id="scoreMap1" type="Score">
<id column="scoreid" property="scoreid"></id>
<result column="couresename" property="couresename"></result>
<result column="score" property="score"></result>
<result column="studentid" property="studentid"></result>
<association property="student" column="studentid" javaType="Student" >
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="height" column="height"></result>
<result property="sAddress" column="s_address"></result>
</association>
</resultMap>
一对多
一对多是在一个类中包含另一个类list
的集合,在映射时,使用Collection
,ofType
为封装类型。
<!--
<collection 解决一对多问题
property="scoreList" 将collection 组成的成绩集合放置到 student对象中
column="id" 根据相同 的学生id组成集合
ofType="Score" 将学生id组成集合 每一个item 生成一个 Score
-->
<resultMap id="studentWithScoreMap" type="Student">
<id column="id" property="id"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="height" column="height"></result>
<result property="sAddress" column="s_address"></result>
<collection property="scoreList" column="id" ofType="Score">
<id property="scoreid" column="scoreid"></id>
<result property="couresename" column="couresename"></result>
<result property="score" column="score"></result>
<result property="studentid" column="id"></result>
</collection>
</resultMap>
多对多
表之间的多对多关系稍微复杂,需要一个中间表来表示。
中间表有三个字段,其中两个字段分别作为外键指向各自一方的主键,由此通过中间表来表示多对多关系,通过一个表联合另一个中间表可以表示为一对多关系。
多对多,其实可以从一方到另一方表示为一对多关系,反之亦然
如:查找学生并包含职位信息
<!--多对多中的一对多-->
<resultMap id="studentWithRole" type="Student">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="height" column="height"></result>
<result property="sAddress" column="s_address"></result>
<collection property="roleList" column="roleid" ofType="Role">
<id property="roleid" column="roleid"></id>
<result property="rolename" column="rolename"></result>
</collection>
</resultMap>
Mybatis中设置的配置文件详解
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
properties属性
properties属性作用:
- 定义全局配置变量
- 加载外部化的properties配置文件
定义全局配置变量,使用 ${} 的表达式如下:
<properties>
<property name="jdbc.driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="123456"/>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
加载外部化配置文件
1.我们先把数据源连接配置到properties文件中,文件名称为jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
2.通过properties标签把上面的properties文件加载进来。
<properties resource="jdbc.properties" />
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
resource/url
只能声明一个文件。resource
跟 url
是互斥的,二者只能取其一。那么如何声明多个文件呢?
通过xml配置的方式是无法实现的。我们可以通过定义Properties对象,加载多个配置文件。通过构造SqlSessionFactory的时候,传入Properties对象。
InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
// 使用Properties的API加载这些properties文件
Properties properties = new Properties();
properties.load(Resources.getResourceAsStream("jdbc1.properties"));
properties.load(Resources.getResourceAsStream("jdbc2.properties"));
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml, properties);
3.配置的优先级
总共配置的方式有三种
(1)直接在 <properties>
中定义配置属性
(2)借助 <properties>
的 resource / url
属性加载外部化配置文件
(3)编程式加载外部化配置文件
按照官方的说法,优先级为:
第一:编程式加载的外部化配置文件
第二:借助 <properties>
的 resource / url
属性加载外部化配置文件
第三:在 <properties>
中定义的配置属性
setting配置
MyBatis 中可供调整的所有内部配置项的全局设置。
typeAliases-类型别名
typeAliases
类型别名的设置,是考虑到 mapper.xml
中我们每次写实体类的时候,都要写它们的全限定类名,太麻烦,于是 MyBatis
提供了类型别名的机制。
<typeAliases>
<!-- 逐个声明 -->
<typeAlias alias="Student" type="com.test.mybatis.entity.Student"/>
<!-- 包扫描
以此法被扫描的实体类,别名为类名的首字母小写形式(类似于Bean -> bean)
-->
<package name="com.test.mybatis.entity"/>
</typeAliases>
typeHandlers-类型处理器
typeHandlers 类型处理器,它的意义是针对一个特定的 Java 类型,或者 jdbc 类型,采用特定的处理器来处理这个类型的字段。
Java 类型和 jdbc 类型之间,用什么类型进行转换,都是这些 typeHandler 干的活。
一般情况下,我们只需要使用 MyBatis 内置的这些 typeHandler 就完全够用。
自定义类型处理器
实现 TypeHandler
接口,并声明其泛型,泛型就是要处理的目标类型。
TypeHandler 接口中定义了 4 个方法。分别对应对方法参数的处理,对返回结果集的处理。
当方法传入的参数为TypeHandler
接口中指定的泛型的时候,如何对PreparedStatement
操作。
当方法返回结果封装时,对于实体类中出现的指定泛型类型的属性时,应该如何从ResultSet中取到数据,并转换为指定类型。
objectFactory-对象工厂
每次查询动作中,数据库返回 ResultSet
时,MyBatis
会根据 statemet
的定义,创建对应的结果对象(跟表对应的实体类对象
)。
创建结果对象的工厂,是一个叫 ObjectFactory
的家伙负责的。
默认情况下,MyBatis
内置了一个 DefaultObjectFactory
来实现结果对象的创建,而我们定义的结果对象通常都有默认的无参构造器,或者有显式定义无参构造器,这样也是方便 DefaultObjectFactory
帮我们创建结果对象。
既然 MyBatis
的全局配置文件中提供了 objectFactory
标签,就说明 MyBatis
允许我们自定义 ObjectFactory
以代替默认的 DefaultObjectFactory
。
如果要自定义对象创建工厂objectFactory
,我们只需要继承DefualtObjectFactory
即可。然后重写创建对象的create
方法。
public class ExtendsObjectFactory extends DefaultObjectFactory {
@Override
public <T> T create(Class<T> type) {
T t = super.create(type);
// 判断是否为User类型,如果是,则预初始化值
if (User.class.equals(type)) {
User user = (User) t;
user.setAge(0);
}
return t;
}
}
然后注册到mybatis-config.xml配置文件中。
<objectFactory type="com.test.mybatis.factory.ExtendsObjectFactory"/>
plugins-插件
MyBatis
的插件实际上就是拦截器
,它可以拦截 MyBatis
的执行流程,并在特定的位置上提供扩展。
Mybatis
提供的可扩展的位置有4个:
Executor
(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler
(getParameterObject, setParameters)
ResultSetHandler
(handleResultSets, handleOutputParameters)
StatementHandler
(prepare, parameterize, batch, update, query)
我们都知道有一个分页插件PageHelper
,它就是基于Mybatis的插件机制实现的。
environments-环境
环境的配置和spring中profile概念差不多。我们数据源的配置都配置在这里。
databaseIdProvider-数据库厂商标识
databaseIdProvider
数据库厂商标识,它为我们提供了数据库可移植性的支持。
我们在编写 mapper.xml
时,针对不同的 statement
,声明不同的数据库厂商标识
,MyBatis
即会动态的根据数据库厂商标识
,使用不同的 statement
,从而达到不同的数据库发送不同 SQL 的效果
。
我们可以在Mybatis-config.xml中配置databaseIdProvider。
<databaseIdProvider type="DB_VENDOR"> <!-- DB_VENDOR是固定的 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
在mapper.xml中进行引用
<select id="findAllByStudentId" parameterType="string"
resultType="com.test.mybatis.entity.Student" databaseId="mysql">
select name,age from gen_studentinfo where id = #{studentId}
</select>
<select id="findAllByStudentId" parameterType="string"
resultType="com.test.mybatis.entity.Student" databaseId="oracle">
<!-- 注意这里查的表不一样 -->
select name,age from gen_studentinfo where id= #{studentId}
</select>
mappers-映射器
配置 mapper.xml 都在这里面写。
三种方式:
1.通过resource
指定加载的mapper.xml。
2.通过class
指定加载的mapper接口。
3.通过package
指定扫描所有mapper接口。使用包扫描时,Mapper接口与对应的mapper.xml放在同一个目录下,且Mapper接口的名称要与mapper.xml的名称一致。(Mapper接口包扫描时会自动寻找同目录下的同名称的mapper.xml文件加载解析)
<mappers>
<mapper resource="mapper/studentMapper.xml"/> <!-- 直接加载mapper.xml -->
<mapper class="com.test.mybatis.mapper.UserMapper"/> <!-- 加载Mapper接口 -->
<package name="com.test.mybatis.mapper"/> <!-- 包扫描Mapper接口 -->
</mappers>