目录
1.3.2 ORM(Object Relational Mapping)
3.10.2 choose元素(when、otherwise)
1. 初识MyBatis
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
官方网站:http://mybatis.org
ORM框架:实体类和SQL语句之间建立映射关系
MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案,适用于性能要求较高或者需求多变的互联网项目
1.1 优点和缺点
优点
- 简单的持久化框架,小巧并简单易学
- 灵活, 不会对应用程序或者数据库的现有设计强加任何影响
- SQL语句封装在配置文件中,便于统一管理与维护,降低程序的耦合度
- 提供XML标签,支持编写动态SQL
- 提供映射标签,支持对象与数据库的ORM字段映射
- 提供对象关系映射标签,支持对象关系组建维护
缺点
- SQL语句编写工作量大,对开发人员有一定要求
- 数据库移植性差
1.2 MyBatis主要组成
- MyBatis的核心对象
- SqlSessionFactoryBuilder(构造器)
- SqlSessionFactory(工厂)
- SqlSession(类似于JDBC的Connection)
- SqlMapper(映射器)
- SqlSessionFactoryBuilder(构造器)
- 常用配置文件
1.3 持久化与ORM
1.3.1 持久化
1.3.2 ORM(Object Relational Mapping)
编写程序的时候,以面向对象的方式处理数据
保存数据的时候,却以关系型数据库的方式存储
ORM解决方案包含下面四个部分
- 在持久化对象上执行基本的增、删、改、查操作
- 对持久化对象提供一种查询语言或者API
- 对象关系映射工具
- 提供与事务对象交互、执行检查、延迟加载以及其他优化功能
2 核心配置文件
2.1 属性配置properties
- 使用resource属性加载外部properties文件
- 使用property子元素配置
- 在SqlSessionFactory执行build方法时增加Properties类型参数
- 优先级:C(最后加载,覆盖之前加载的) > A > B(最先加载)
2.2 全局配置settings
- 日志logImpl:配置日志类型,常用LOG4J、SLF4J
- 允许使用别名useColumnLabel:默认true,改为false则无法使用列的别名进行自动映射,必须配置映射关系
- 获取自增值useGeneratedKeys:默认false,全局配置,设为true后所有映射文件中需要获取自增值时就无需配置该属性了
2.3 别名配置typeAliases
- 使用typeAlias子元素的type(类型全名)和alias(自定义别名)属性逐一配置别名
- 使用package子元素的name属性给整个包中的类配置别名(类的简单名)
2.4 运行环境配置environment
事务管理器:目前使用jdbc方式
<transactionManager type="JDBC"/>
数据源:可以使用非连接池UNPOOLED、MyBatis的连接池POOLED以及JNDI方式
配置Tomcat的JNDI:
- 在META-INF下创建context.xml文件,配置数据源连接池参数(注意&符号的写法)
<Context>
<Resource
name="jdbc/mysql"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/d183003?useUnicode=true&characterEncoding=utf8"
username="root"
password="123456"
maxIdle="2"
maxWaitMillis="5000"
maxTotal="10"/>
</Context>
- 在MyBatis核心配置文件中加environment元素(其中initial_context是固定写法,data_source与上步的name对应)
<environment id="tomcat">
<transactionManager type="JDBC"/>
<dataSource type="JNDI">
<property name="initial_context" value="java:comp/env"/>
<property name="data_source" value="jdbc/mysql"/>
</dataSource>
</environment>
- 运行时指定所使用的environment的id(builder.build(is,”tomcat”);)
3. 映射文件
MyBatis 真正的强大在于映射语句,专注于SQL,功能强大,SQL映射的配置却是相当简单
SQL映射文件的几个顶级元素(按照定义的顺序)
mapper – namespace
- cache – 配置给定命名空间的缓存
- cache-ref – 从其他命名空间引用缓存配置
- resultMap –用来描述数据库结果集和对象的对应关系
- sql – 可以重用的SQL块,也可以被其他语句引用
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
3.1 mapper元素
namespace:命名空间
namespace和子元素的id联合保证唯一,区别不同的mapper
绑定DAO接口
- namespace的命名必须跟某个接口同名
- 接口中的方法与映射文件中SQL语句id一一对应
实例
<mapper namespace="cn.smbms.dao.user.UserMapper">
<select id="getUserList" …>
……
</select>
</mapper>
3.2 sql元素
简化sql语句中相同的部分
实例
<sql id="selM">select * from movie</sql>
<select id="getMovie" parameterType="int" resultType="Movie" >
<include refid="selM"/> where mid=#{id}
</select>
<select id="getAll" resultType="Movie" >
<include refid="selM"/>
</select>
3.3 resultMap元素
当表的列名与实体类的属性名不一致时,除了通过列的别名(前提是全局配置中允许使用别名useColumnLabel为true),还可以通过该元素进行映射配置
- 配置resultMap:type属性是原始类型全名或简单名(如果配置过);id属性给select元素使用;id子元素用于映射主键列;result子元素用于映射其它列;column是表中的列名(不区分大小写),property是实体类的属性名(区分大小写)
实例
<resultMap type="hall" id="hm">
<id column="hid" property="id"/>
<result column="cid" property="cinemaId" />
</resultMap>
- 使用resultMap:在select元素中使用resultMap属性替代resultType属性,其值与上步中的id属性值对应
实例
<select id="getAll" resultMap="hm">
<include refid="selH"/>
</select>
3.4 Select
属性 | 描述 |
id | 在命名空间中唯一的标识符,可以被用来引用这条语句 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名 |
resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。注意集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用resultType或resultMap,但不能同时使用 |
resultMap | 命名引用外部的resultMap |
flushCache | 将其设置为true,不论语句什么时候被调用,都会导致缓存被清空。默认值:false |
useCache | 将其设置为true,将会导致本条语句的结果被缓存。默认值:true |
timeout | 这个设置驱动程序等待数据库返回请求结果,并抛出异常时间的最大等待值。默认不设置(驱动自行处理) |
fetchSize | 这是暗示驱动程序每次批量返回的结果行数 |
statementType | STATEMENT,PREPARED或CALLABLE的一种。让MyBatis选择使用Statement,PreparedStatement或CallableStatement。默认值:PREPARED |
resultSetType | FORWARD_ONLY|SCROLL_SENSITIVE|SCROLL_INSENSITIVE中的一种。默认是不设置(驱动自行处理) |
id
命名空间中唯一的标识符
接口中的方法与映射文件中的SQL语句id一一对应
parameterType
基础数据类型
- int、String、Date等
- 只能传入一个,通过#{参数名}即可获取传入的值
复杂数据类型
- Java实体类、Map等
- 通过#{属性名}或者#{map的keyName}即可获取传入值
resultType/resultMap
resultType :直接表示返回类型
- 基本数据类型
- 复杂数据类型
resultMap :对外部resultMap的引用
应用场景:
- 数据库字段信息与对象属性不一致
- 复杂的联合查询,自由控制映射结果
二者不能同时存在,本质上都是Map数据结构
3.5 insert、update、delete
- id
- parameterType
注意:insert、update、delete元素均没有resultType属性
3.6 resultMap
property:表示查询出来的属性对应的值赋给实体对象的哪个属性
column:从数据库中查询的列名或者别名
resultMap自动映射匹配
resultMap自动映射匹配前提:字段名与属性名一致
resultMap的自动映射级别-autoMappingBehavior
- NONE:禁止自动匹配
- PARTIAL(默认):自动匹配所有属性,内部嵌套除外
- FULL:自动匹配所有
实例
<!-- 全局配置文件中配置 -->
<settings>
<setting name="autoMappingBehavior" value="NONE"/>
</settings>
resultMap实例
<resultMap type="User" id="userList">
<result property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
<result property="userRole" column=“userRole"/>
<result property="userRoleName" column="roleName"/>
</resultMap>
3.7 一对一的配置
association
复杂的类型关联,一对一
内部嵌套
映射一个嵌套JavaBean属性
属性
property:映射数据库列的实体对象的属性
javaType:完整Java类名或者别名
resultMap:引用外部resultMap
子元素
id
result
- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
3.8 一对多的配置
collection
复杂类型集合,一对多
内部嵌套
映射一个嵌套结果集到一个列表
属性
property:映射数据库列的实体对象的属性
ofType:完整Java类名或者别名(集合所包括的类型)
resultMap:引用外部resultMap
子元素
id
result
- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
3.9 缓存的配置
MyBatis缓存
- 一级缓存
- 二级缓存
二级缓存的配置
- MyBatis的全局cache配置
- 在Mapper XML文件中设置缓存,默认情况下是没有开启缓存的
- 在Mapper XML文件配置支持cache后,如果需要对个别查询进行调整,可以单独设置cache
实例
<!-- 全局配置配置 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
<select id="selectAll" resultType="Emp" useCache="true">
3.10 动态sql
基于OGNL表达式
完成多条件查询等逻辑实现
3.10.1 If
用于条件判定,属性test,使用OGNL语法,无需添加#{...},示例如下(注意使用WHERE 1=1的目的)
实例:
<select id="selCinemaByNameAddress" parameterType="cinema" resultType="cinemavo">
select cid id ,name,address from cinema where 1=1
<if test="name!=null">
and name like '%${name}%'
</if>
<if test="address!=null">
and address like '%${address}%'
</if>
</select>
3.10.2 choose元素(when、otherwise)
包含子元素when和otherwise
实例:
<select id="getMovieByPrice5" parameterType="map"
resultType="Movie" >
<include refid="selM"/>
<choose>
<when test="minPrice!=null and maxPrice==null">
where price>=#{minPrice}
</when>
<when test="maxPrice!=null and minPrice==null">
where price<=#{maxPrice}
</when>
<when test="maxPrice!=null and minPrice!=null and minPrice lt maxPrice">
where price between #{minPrice} and #{maxPrice}
</when>
</choose>
</select>
3.10.3 trim
可代替where、set,也可以控制其它语句的结构,主要包含prefix(要增加的前缀)、prefixOverrides(要去除的前缀,多个使用|分隔)、suffix(要增加的后缀)、suffixOverrides(要去除的后缀)
3.10.4 where
自动添加where关键字,且返回语句以and或or开头的会被自动去除
实例
<select id="selCinemaByNameAddress2"
parameterType="cinema" resultType="cinemavo">
select cid id ,name,address from cinema
<where>
<if test="name!=null">
name like '%${name}%'
</if>
<if test="address!=null">
and address like '%${address}%'
</if>
</where>
</select>
3.10.5 set
用于update元素
实例
<update id="modify" parameterType="movie">
update movie
<set>
mid=#{mid},<!-- 增加该语句的目的是防止两个条件都不成立 -->
<if test="name!=null">name=#{name},</if>
<if test="price gt 0">price=#{price}</if>
</set>
where mid=#{mid}
</update>
3.10.6 foreach
主要包含collection(遍历的类型,list或array)、item(每次遍历到的数据)、open(增加的起始字符)、close(增加的结尾字符)、separator(每次遍历之间的分割字符)等属性
<update id="modifyPrice" parameterType="list">
update movie set price=price+1 where mid in
<foreach collection="list" item="id"
separator="," open="(" close=")">
#{id}
</foreach>
</update>
4. 核心对象
4.1 SqlSessionFactoryBuilder
用过即丢,其生命周期只存在于方法体内
可重用其来创建多个 SqlSessionFactory 实例
负责构建SqlSessionFactory,并提供多个build方法的重载
常用构造
配置信息以三种形式提供给SqlSessionFactory的build方法:
InputStream (字节流)、Reader(字符流)、Configuration(类)
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties);
public SqlSessionFactory build(Reader reader, String environment, Properties properties);
public SqlSessionFactory build(Configuration config);
读取XML文件构造方式
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
4.2 SqlSessionFactory
SqlSessionFactory是每个MyBatis应用的核心
作用:创建SqlSession实例
作用域:Application
生命周期与应用的生命周期相同
单例:存在于整个应用运行时,并且同时只存在一个对象实例
实例
SqlSession session = sqlSessionFactory.openSession();
SqlSession session = sqlSessionFactory.openSession(boolean autoCommit);
注意:openSession方法可传入参数,表示是否 自动提交事物
4.3 SqlSession
包含了执行SQL所需的所有方法
对应一次数据库会话,会话结束必须关闭
线程级别,不能共享
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
注:在SqlSession里可以执行多次SQL语句,但一旦关闭了SqlSession就需要重新创建
4.3.1 SqlSession的获取方式
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is) ;
SqlSession sqlSession = factory.openSession();
4.3.2 SqlSession的两种使用方式
- 通过SqlSession实例直接运行映射的SQL语句
- 基于Mapper接口方式操作数据
5. 简单框架搭建
注:不是最优化方案,只是一个方便学习的实例。
- 下载mybatis-3.2.x.jar包并导入工程
- 编写MyBatis核心配置文件
- 创建实体类-POJO
- DAO层-SQL映射文件(XxxMapper.xml)
- 创建测试类
5.1 核心文件配置实例
核心文件
<?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元素的子元素进行配置(不常用) -->
<properties resource="datasource.properties"></properties>
<!-- 设置选项,用于设置和改变MyBatis 运行中的行为 -->
<settings>
<!-- 日志配置 -->
<setting name="logImpl" value="LOG4J" />
<!-- 设置查询数据库超时时间 (默认值:Not Set (null)) -->
<setting name="defaultStatementTimeout" value="25000" />
<!-- 指定 MyBatis 是否以及如何自动将列映 射到字段/属性。 PARTIAL(默认): 只是自动映射简单、非嵌套 的结果集。 FULL:
将会自动映射任何复杂的(嵌套 或非嵌套)的结果集 -->
<setting name="autoMappingBehavior" value="FULL" />
<!-- 除了需求外,以下属性一般无需特意配置 -->
<!-- 全局性地启用或禁用所有在mapper配置文件中配置的缓存。(默认值:true) -->
<setting name="cacheEnabled" value="true" />
<!-- 全局性地启用或禁用延迟加载。当禁用时,所有关联的配置都会立即加载。(默认值:true) -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 允许或禁止从单一的语句返回多个结果集(默认值:true) -->
<setting name="multipleResultSetsEnabled" value="true" />
<!-- 使用列的标签而不是列的名称(默认值:true) -->
<setting name="useColumnLabel" value="true" />
<!-- 允许JDBC自动生成主键(默认值:false) -->
<setting name="useGeneratedKeys" value="false" />
<!-- 是否启用字节码增强机制 -->
<setting name="enhancementEnabled" value="false" />
<!-- 配置默认的执行器(executor)。 SIMPLE(默认):简单的执行器。 REUSE :重用prepared statements的
执行器。 BATCH:重用 statements并且进行批量 更新的执行器。 -->
<setting name="defaultExecutorType" value="SIMPLE" />
</settings>
<!-- 实体类型别名配置,减少输入多余的完整类名 -->
<typeAliases>
<!-- <typeAlias alias="Student" type="cn.kgc.pojo.Student"/> 别名匹配,比较繁琐,不推荐使用 -->
<!-- 包名匹配 -->
<package name="cn.cs.pojo" />
</typeAliases>
<!-- 不常用配置,本实例没有配置 -->
<!--typeHandlers:重写类型处理器(type handlers)后,在此配置映射 -->
<!-- objectFactory:重写 ObjectFactory后,在此配置映射 -->
<!-- 插件配置:需要时配置 -->
<plugins>
<!-- 分页插件配置 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="mysql" />
</plugin>
</plugins>
<!-- 运行环境配置。可以配置多个运行环境,但是每个SqlSessionFactory 实例只能选择一个运行环境。 -->
<environments default="development">
<environment id="development">
<!-- 事物管理器 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源 -->
<dataSource type="POOLED">
<!-- 简单数据源配置,详细配置请自行百度 -->
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- SQL映射类配置,减少输入多余的完整类名 -->
<mappers>
<!-- <mapper resource="cn/kgc/dao/StudentMapper.xml"/> 全名称匹配,不推荐使用 -->
<!-- 包名匹配 -->
<package name="cn.cs.dao" />
</mappers>
</configuration>
database.properties数据库配置
driverClassName=com.mysql.jdbc.Driver
#在和mysql传递数据的过程中,使用unicode编码格式,并且字符集设置为utf-8
url=jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=utf-8
username=root
password=root
补充:
属性能够被可动态替换(即使用占位符)的属性值引用 如:${driver},引用properties配置文件键后的值
5.2 实体类和映射文件
sql映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<mapper namespace="cn.kgc.dao.StudentMapper">
<select id="getStudents" resultType="Student">
select * from student
</select>
<update id="updateStu" parameterType="Student">
update student set sName=#{sName} where id = #{id}
</update>
<delete id="addStu" parameterType="Student">
insert into student(sName,age,addres) values(#{sName},#{age},#{addres})
</delete>
<insert id="delstu">
delete from student where id = #{id}
</insert>
</mapper>
实体类
public class Student {
private int id;
private String sName;
private int age;
private String addres;
public Student() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddres() {
return addres;
}
public void setAddres(String addres) {
this.addres = addres;
}
@Override
public String toString() {
return "Strudent [id=" + id + ", sName=" + sName + ", age=" + age + ", addres=" + addres + "]";
}
}
- 实体类POJO,按照数据库中对应表的结构编写
- 映射文件按照给定模板编写
- 根元素mapper,指定namespace
- 当属性名与列名不一致时,定义resultMap进行映射
- 定义CRUD标签(select、insert、delete、update),编写SQL语句
- 每个标签指定id用于查找;parameterType属性指定参数类型;resultMap指定返回值类型
5.3 MybatisUtils工具类与测试类
MybatisUtils工具类
public class MybatisUtils {
private static SqlSessionFactory factory;
// 在static里,factory只会被建立一次
static {
try {
// 获取config.xml的输入流
InputStream is = Resources.getResourceAsStream("config.xml");
//工厂建造器build()方法创建sqlSession 工厂
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
// 建立sqlsession
public static SqlSession createSqlSession() {
return factory.openSession(true); // true: 自动提交事物
}
// 释放资源
public static void close(SqlSession sqlSession) {
if (null != sqlSession) {
sqlSession.close();
}
}
}
2.3.4 SqlSession的两种使用方式
StudentMapper接口
public interface StudentMapper {
//1.查询学生表的记录数
public int count();
}
通过SqlSession实例直接运行映射的SQL语句
@Test
public void test1() throws IOException {
SqlSession se=null;
se=MybatisUtils.createSqlSession();
//通过SqlSession实例直接运行映射的SQL语句
int count=se.selectOne("cn.kgc.dao.StudentMapper.count");
System.out.println(count);
MybatisUtils.close(se);
}
基于Mapper接口方式操作数据
@Test
public void test2() throws IOException {
SqlSession se=MybatisUtils.createSqlSession();
//基于Mapper接口方式操作数据
int count= se.getMapper(StudentMapper.class).count();
System.out.println(count);
MybatisUtils.close(se);
}
注意:方式2要求Mapper接口的名称必须和映射文件中mapper元素的namespace属性完全一致,方式1则无此要求;另外Mapper接口中的方法名需和映射文件中相应元素的id属性对应