基础知识
什么是Mybatis
它是一款基于java的半自动ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低。
什么是ORM?
Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的Student类,去对应数据库中的一张student表,类中的属性和表中的列一一对应。Student类就对应student表,一个Student对象就对应student表中的一行数据
为什么mybatis是半自动的ORM框架?
用mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。用hibernate开发,只需要定义好ORM映射关系,就可以直接进行CRUD操作了。由于mybatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialect),所以mybatis的数据库无关性低。虽然mybatis需要手写SQL,但相比JDBC,它提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提升了开发的效率。并且它的学习成本也比hibernate低很多
特性
参数解析
$():表示一个拼接符号,仅仅为一个纯碎的string替换,在动态SQL解析阶段将会进行变量替换。
():表示一个占位符号,解析为一个JDBC预编译语句(prepared statement)的参数标记符,一个#{}
被解析为一个参数占位符。
Mybatis执行流程
图示流程
详细流程
(1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。
(2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
(3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。
(4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。
(5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。
(6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。
(7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。
(8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。
Mybatis开发Dao层
开发方式
传统开发方式
需要创建Dao层Mapper接口和其实现类,再手动创建其实现类对象进行方法调用
接口代理开发方式(主流)
仅需编写Dao层Mapper接口,由Mybatis的mapper代理自动创建接口的实现类,最后由mapper代理对象调用方法
Mapper接口代理开发需要遵循以下规范
映射配置文件中的namespace与mapper接口的类名相同
映射配置文件中的增删改查标签的id属性要和Mappe接口中的方法名相同
映射配置文件中的增删改查标签的parameterType属性要和Mappe接口中的方法参数相同
映射配置文件中的增删改查标签的resultType属性要和Mappe接口中方法的返回值相同
示例
UserMapperProxy.java
public interface UserMapperProxy {
public List<User> getAllUser();
}
UserMapperProxy.xml
<mapper namespace="com.example.dao.UserMapperProxy">
<select id="getAllUsers" resultType="user">
select * from user;
</select>
</mapper>
两种开发方式demo
//传统方式
UserMapperManualImpl userMapper = new UserMapperManualImpl();
List list = userMapper.userList();
System.out.println(list);
//接口代理方式
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapperProxy mapperProxy = sqlSession.getMapper(UserMapperProxy.class);
List<User> allUsers = mapperProxy.getAllUser();
System.out.println(allUsers);
Mybatis基于配置文件的开发
导入相关依赖
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
</dependencies>
创建实体类数据库表
创建user表
创建数据表对应java类
创建user类
package com.example.domain;
import java.util.Date;
public class User {
private int id;
private String name;
private int money;
private Date birthday;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
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 int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
", birthday=" + birthday +
'}';
}
}
填写数据库的连接信息
示例
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=123456
创建Dao层mapper接口
package com.example.mapper;
import com.example.domain.User;
import java.util.List;
public interface UserMapper {
public void addUser(User user);
public User queryUserById(int id);
public List<User> getAllUser();
}
创建mapper接口映射文件
配置文件标签
约束头
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
根标签
<mapper></mapper>
根标签属性
namespace:根标签的唯一限定名
子标签
子标签名称 | 功能 |
---|---|
select | 查询语句 |
delete | 删除语句 |
update | 修改语句 |
insert | 插入语句 |
cache | |
cache-ref | |
parameterMap | |
resultMap | |
sql | sql语句片段抽取 |
子标签属性
属性名 | 含义 |
---|---|
id | 子标签的唯一限定名 |
parameterType | 指定传入的参数的类型 |
resultType | 指定查询语句的结果类型 |
parameterMap | |
resultMap | |
databaseId | |
fetchSize | |
flushCache | |
lang | |
... |
⭐动态SQL
根据用户输入或外部条件动态组合的SQL语句块。
all
元素 | 作用 | 备注 |
---|---|---|
if | 判断语句 | 单条件分支判断 |
choose(when、otherwise) | 相当于java中的switch case语句 | 多条件分支判断 |
foreach | 循环语句 | 常用在in语句等列举条件中 |
trim,where | 辅助元素 | 用于除里一些SQL拼装问题 |
bind | 辅助元素 | 拼接参数 |
if
对业务提交的数据进行判断,动态地生成需要执行的SQL语句
select * from user where id=#{id} and name=#{name} and money=#{money};
<select id="getUserByCondition" resultType="user" parameterType="user">
select * from user
<where>
<if test="id!=0">
id=#{id}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="money!=0">
and money=#{money}
</if>
</where>
</select>
foreach
select * from user where id in (1,2,3);
<select id="getUserByCollection" resultType="user" parameterType="list" >
select * from user
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</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="userMapper">
<select id="queryById" resultType="user" parameterType="int">
select * from user where id = #{id}
</select>
<select id="queryAll" resultType="user">
select * from user;
</select>
<insert id="insertOne" parameterType="user">
insert into user values(#{id},#{name},${money})
</insert>
<update id="updateById" parameterType="int">
update user set money = #{money} where id=#{id}
</update>
<delete id="deleteByName" parameterType="string">
delete from user where name = #{name}
</delete>
</mapper>
创建xml核心配置文件
配置文件介绍
约束头
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
根标签
<configuration></configuration>
子标签
all
*号为常用标签
子标签名称 | 功能 |
---|---|
properties | 加载外部的properties文件 |
environments | 数据源环境, |
databaseIdProvider | 数据库厂商标识, |
mappers | 加载映射配置, |
objectFactory | 对象工厂, |
objectWrapperFactory | 对象包装工厂, |
plugins | 插件, |
reflectorFactory | 反射器工厂, |
settings | 设置, |
typeAliases | 类型别名, |
typeHandlers | 类型处理器, |
properties
properties存在子标签property
父标签 | 属性名 | 功能 |
---|---|---|
properties | resource | 从项目的resources文件夹内加载资源 |
url | 从远程URL加载资源 |
<properties resource="jdbc.properties"/>
<properties url="http://xxxx/jdbc.properties"/>
environments
父标签 | 子标签1 | 子标签2 | 子标签3 | 属性 | 可选值 | 属性功能 |
---|---|---|---|---|---|---|
environments | default | development | 指定默认的环境名称 | |||
environment | id | 指定当前环境的名称 | ||||
transactionManager | type | JDBC | 指定事务管理器 | |||
MANAGED | ||||||
dataSource | type | POOLED | 指定数据源类型 | |||
UNPOOLED | ||||||
JNDI | ||||||
property | name | |||||
value | 可使用el表达式设置值 |
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
mappers
父标签 | 子标签1 | 属性名 | 属性功能 |
---|---|---|---|
mappers | mapper | resource | 使用相对于类路径的资源引用 |
url | 使用完全限定资源定位符(URL) | ||
class | 使用映射器接口实现类的完全限定类名 | ||
package | name | 将包内所有的映射器接口全部注册为映射器 |
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<package name="org.mybatis.builder"/>
</mappers>
typeAliases
父标签 | 子标签1 | 属性名 | 属性功能 |
---|---|---|---|
typeAliases | typeAlias | type | 需要指定类(类全限定名) |
alias | 别名的名称 |
<typeAliases>
<typeAlias type="org.example.domain.User" alias="user"/>
</typeAliases>
typeHandlers
父标签 | 子标签1 | 属性名 | 属性功能 |
---|---|---|---|
typeHandlers | typeHandler | handler | 指定handler类全限定名 |
<typeHandlers>
<typeHandler handler="com.example.handler.DateTypeHandler"></typeHandler>
</typeHandlers>
plugins
父标签 | 子标签1 | 子标签2 | 属性名 | 属性功能 |
---|---|---|---|---|
plugins | plugin | interceptor | 指定使用的插件的类全限定名 | |
property | name | |||
value |
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
代码示例
<?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="jdbc.properties"/>
<typeAliases>
<typeAlias type="org.example.domain.User" alias="user"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<mappers>
<mapper resource="org/example/mapper/userMapper.xml"></mapper>
</mappers>
</configuration>
编写测试类
Mybatis的API使用
SqlSessionFactoryBuilder
SqlSession工厂构建器,通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
SqlSessionFactory
SqlSession工厂对象,创建SqlSession对象
//需要手动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession();
//设置自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
SqlSession
SqlSession会话对象,通过对象来执行sql语句、操作事务等
sqlSession.getMapper()//接口代理
sqlSession.select()//CRUD
sqlSession.commit()
sqlSession.close()
代码示例
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("userMapper.queryAll");
sqlSession.commit();
System.out.println(list);
sqlSession.close();
Mybatis基于注解的开发
创建实体类数据库表
创建数据表对应java类
⭐创建Dao层mapper映射接口
package com.example.mapper;
import com.example.domain.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface UserMapper {
@Insert("insert into user values(#{id},#{name},#{money},#{birthday})")
public void save(User user);
@Update("update user set name=#{name},money=#{money} where id=#{id}")
public void update(User user);
@Delete("delete from user where id=#{id}")
public void delete(int id);
@Select("select * from user where id=#{id}")
public User findById(int id);
@Select("select * from user")
public List<User> findAll();
}
创建properties属性文件
创建xml核心配置文件
与配置文件开发不同的唯一一点是注解开发mappers采用加载package包来加载
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加载properties文件-->
<properties resource="jdbc.properties"></properties>
<!-- 数据源环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<!-- 映射器-->
<mappers>
<package name="com.example.mapper"/>
</mappers>
</configuration>