Mybatis支持普通sql操作,存储过程的调用,它是一个高级的ORM框架(Object Relation Mapping对象关系映射–以面向对象思想访问数据库),是一个基于Java的持久层框架。
MyBatis封装了几乎所有的JDBC操作和参数的手工设置,它会对结果集自动封装成对象,以及直接把对象存入数据库,甚至可以做到对象与对象的关系维护;诸如:建立连接、操作 Statment、ResultSet,处理 JDBC 相关异常等等都可以交给 MyBatis 去处理,我们的关注点于是可以就此集中在 SQL 语句上,关注在增删改查这些操作层面上。
1. Mybatis框架的构成
- 实体类 : 封装记录信息(JavaBean)
- SQL定义文件 :定义sql语句(编写SQL语句的XML)
- 主配置文件 :定义连接信息、加载SQL文件 以及其他设置的XML
- 框架API :用于实现数据库增删改查操作(主要通过SqlSession)
2. 使用Mybatis访问数据库
以员工表Emp(id,name,salary)
为例
准备数据库及创建项目(需要mybatis的jar包和数据库驱动包)
根据表建立对应的实体类:
Emp(id,name,salary)
在「src」目录下创建 MyBaits 的主配置文件 mybatis-config.xml ,其主要作用是提供连接数据库用的驱动,数据名称,编码方式,账号密码等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<configuration>
<environments default="environment">
<environment id="environment">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver"
value="com.mysql.cj.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mapper/EmpMapper.xml" />
</mappers>
</configuration>在「src」包路径下创建配置文件(com/mapper/EmpMapper.xml),然后根据需求定义sql
1
2
3
4
5
6
7
8
9
10
11<mapper namespace="com.mapper.EmpMapper">
<!-- 定义SQL语句 -->
<select id="findById" parameterType="int"
resultType="com.mapper.Emp">
select * from emp32 where id = #{id}
</select>
<select id="findByName" parameterType="String"
resultType="com.mapper.Emp">
select * from emp32 where name = #{name}
</select>
</mapper>- parameterType:要求输入参数的类型
- resultType:输出的类型
封装工具类获取SQLSession
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class SqlSessionUtil {
public static SqlSessionFactory ssf;
static {
// 先构建SQLSession工厂构建器
SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
// 构建SqlSessionFactory关联主配置文件
InputStream inputStream = SqlSessionUtil.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
ssf = ssfb.build(inputStream);
}
// 获取SQLSession
public static SqlSession getSqlSession() {
// 通过SqlSession 工厂对象 来获取SqlSession
return ssf.openSession();
}
}编写测试类
1
2
3
4
5
6
7public class EmpTest {
public static void main(String[] args) {
SqlSession ss =SqlSessionUtil.getSqlSession();
Emp emp = ss.selectOne("findById", 6);
System.out.println(emp);
}
}
基本原理
- 应用程序找 MyBatis 要数据
- MyBatis 从数据库中找来数据
- 通过 mybatis-config.xml 定位哪个数据库
- 通过 EmpMapper.xml 执行对应的 sql 语句
- 基于 EmpMapper.xml 把返回的数据库封装在 Emp 对象中
- 返回一个 Emp 对象
3. Mybatis的CRUD操作
以员工表Emp(id,name,salary)
为例
- 第一步:配置EmpMapper.xml
1 | <insert id="insertEmp" parameterType="com.mapper.Emp"> |
- parameterType:要求输入参数的类型
- resultType:输出的类型
- 第二步:SQLSession实现增删改查
1 | // 先构建SQLSession工厂构建器 |
SqlSession对象的操作方法如下:
- insert(..) 插入操作
- update(..) 更新操作
- delete(..) 删除操作
- selectOne(..) 单行查询操作
- selectList(..) 多行查询操作
- 通过 session.commit() 来提交事务,也可以简单理解为更新到数据库
4. Mapper映射器
使用规则:
- 接口的方法名和SQL定义文件中的id保持一致
- 接口方法的返回值类型 要和resultType 保持一致
- 单行:
resultType
- 多行:
List<resultType>
- 增删改返回值,推荐int,也可以是void
- 单行:
- 接口方法参数和parameterType保持 一致,如果没有parameterType则参数任意
- SQL定义文件中的namespace必须包名.接口名
5. 向mapper传多个参数
5.1 第一种方案:#{0},#{1} / #{param1} 和 #{param2}
DAO层的函数方法
1 | public Emp findByIdAndName(int id, String name); |
对应的Mapper.xml
1 | <select id="findByIdAndName" resultType="com.bean.Emp"> |
其中,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
也可以用#{param1} 和 #{param2}实现同意效果。
5.2 第二种方案@param
Dao层的函数方法
1 | public Emp findByIdAndName(int id, String name); |
对应的Mapper.xml
1 | <select id="findByIdAndName" resultType="com.bean.Emp"> |
5.3 第三种方案:采用对象或Map传多参数
Dao层的函数方法
1 | public Emp findByIdAndName(Emp emp); |
对应的Mapper.xml
1 | <select id="findByIdAndName" parameterType="com.bean.Emp" resultType="com.bean.Emp"> |
6. 结果集列名和属性名不一致的解决方法
在SQL定义中,resultType属性用于指定查询数据采用哪种类型封装,规则为结果集列名和属性名一致,如果不一致将不能接收查询结果。
解决方法:
- 使用别名,select语句使用与属性一致的别名
- 使用resultMap替换resultType,用resultMap指定结果集列名和属性名的对应关系
1 | <!-- 定义resultMap将sql 结果集列名(数据库中的字段)和Emp类中的属性做一个映射关系 |
7. 类型的别名和日志输出
在mybatis-config.xml中自定义类型的别名
1 | <typeAliases> |
在EmpMapper.xml中使用别名 resultType=”emp”
1 | <select id="findById" parameterType="int" resultType="emp"> |
设置MyBatis的日志输出到控制台
1 | <settings> |
8. JdbcType
在执行SQL时MyBatis会自动通过对象中的属性给SQL中参数赋值,它会自动将Java类型转换成数据库的类型。而一旦传入的是null它就无法准确判断这个类型应该是什么,就有可能将类型转换错误,从而报错。
- 所以 MyBatis 插入空值时,需要指定JdbcType,这样相对来说是比较安全的。
- 一般情况下,我们没有必要按个字段去识别/判断它是否可以为空,而是将所有的字段都当做可以为空,全部手动设置转换类型。
- MyBatis包含的JdbcType类型,主要有下面这些:
- BIT、FLOAT、CHAR 、TIMESTAMP 、 OTHER 、UNDEFINEDTINYINT 、REAL 、VARCHAR 、BINARY 、BLOB NVARCHAR、SMALLINT 、DOUBLE 、LONGVARCHAR 、VARBINARY 、CLOB、NCHAR、INTEGER、 NUMERIC、DATE 、LONGVARBINARY 、BOOLEAN 、NCLOB、BIGINT 、DECIMAL 、TIME 、NULL、CURSOR
1 | <select id="findByName" parameterType="String" resultType="com.bean.Emp"> |
9. Mabatis中#{}和${}的区别
${}
是字符串替换,底层使用的Statement(sql注入问题,效率低,编写sql复杂)- 支持${param1}或${变量名},不支持${0},Dao层必须使用@Param(),用到字符串时需要手动加单引号
#{}
是预编译处理命令,底层使用PreparedStatement(可以有效防止sql注入)- 不支持表名、排序方式等的占位,默认会将其当成字符串
10. 分页
- 在主配置文件中配置 分页拦截器(依赖于pageHelper、sqlparse相关jar)
1 | <!-- 配置分页拦截器 --> |
- 查询前使用分页API
1 | PageHelper.startPage(2, 2); |
11. Spring+MyBatis整合
Spring与MyBatis整合需要引入一个mybatis-spring.jar文件包,该包提供了下面几个与整合相关的API:
- SqlSessionFactoryBean
- 创建SqlSessionFactory对象,为整合应用提供SqlSession对象资源
- 依赖于dataSource 和加载SQL定义文件
- MapperFactoryBean
- 根据指定的某一个Mapper接口生成Bean实例
- 依赖于SqlSessionFactory 和 MApper接口
- MapperScannerConfigurer
- 根据指定包批量扫描Mapper接口并生成实例
- SqlSessionTemplate
- 类似于JdbcTemplate,便于程序员自己编写Mapper实现类
12. Spring+MyBatis完成sql操作
第一步:使用Mybatis(同上)
- 导jar包(mybatis包/数据库驱动包),建立实体类,定义SQL文件,编写Mapper映射接口
第二步:配置SqlSessionFactoryBean
- 导入jar包(mabatis-spring/ioc/aop/dao/连接池)
- 配置SqlSessionFactoryBean注入dataSource和指定sql定义文件
1 | <!-- 配置SqlSessionFactory --> |
第三步:
- 方式一: 使用SqlSessionFactoryBean结合接口和SqlSessionFactory
- 最终产生Mapper接口的 实现类,注意这是实现类
1 | <!-- 配置SqlSessionFactoryBean 产生Mapper接口的 实现类 --> |
- 方式二: MapperScannerConfigurer
- MapperFactoryBean一次只能生产一个DAO的实现类,可以通过MapperScannerConfigurer批量生产DAO接口实现类
1 | <!-- 批量生产DAO接口实现类 ,实现类id为类名首字母小写 --> |
13. 使用SqlSessionTemplate模板来完成DAO接口的实现类
- 使用Mybatis(同上)
- 配置SqlSessionFactoryBean(同上)
- 编写DAO接口的实现类
- 开启组件扫描,注入SqlSessionTemplate,依赖于SqlSessionFactory
- 使用SqlSessionTemplate对应API完成增删改查
1 | <!-- 开启组件扫描 --> |
1 |
|