MyBatis主要涉及两个核心对象:SqlSessionFactory和SqlSession
1.MyBatis核心对象
-
SqlSessionFactory
SqlSessionFactory它是单个数据库映射关系经过编译后的内存镜像,其主要作用是创建SqlSession.
通过xml构建出SqlSessionFactory实例的代码如下:
//读取配置文件
InputStream inputstream=Resources.getResourcesAsStream("配置文件位置");
//根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputstream);
SqlSessionFactory对象是线程安全的,它一旦被创建,在整个应用执行期间都会存在.
-
SqlSession
SqlSession是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作.
SqlSession对象包含了数据库中所有执行SQL操作的方法,由于其底层封装了JDBC连接,所以可以直接使用其实例来执行已映射的SQL语句.每一个线程都应该有一个自己的SqlSession实例,并且该实例是不能被共享的.同时,SqlSession实例也是线程不安全的,因此其使用范围最好在一次请求或一个方法中,决不能将其放在一个类的静态字段、实例字段或任何类型的管辖范围(如Servlet的HttpSession)中使用.使用完SqlSession对象之后,要及时的关闭它,通常可以将其放在finally块中关闭
SqlSession sqlSession =SqlSessionFactory.openSession();
try{
//此处执行持久化操作
}finally{
sqlSession.close();
}
方法名 | 描述 |
<T>T selectOne(String statement); | 查询方法.参数statement是在配置文件中定义的<select>元素的id.使用该方法后会返回执行SQL语句查询结果的一条泛型对象 |
<T>T selectOne(String statement,Object parameter); | 查询方法.参数statement是在配置文件中定义的<select>元素的id.parameter是查询所需要的参数.使用该方法后会返回执行SQL语句查询结果的一条泛型对象 |
<E> List<E> selectList(String statement); | 查询方法.参数statement是在配置文件中定义的<select>元素的id.使用该方法后会返回执行SQL语句查询结果的泛型对象的集合 |
<E> List<E> selectList(String statement,Object parameter); | 查询方法.参数statement是在配置文件中定义的<select>元素的id.parameter是查询所需要的参数.使用该方法后会返回执行SQL语句查询结果的泛型对象的集合 |
<E> List<E> selectList(String statement,Object parameter,RowBounds rowBounds); | 查询方法.参数statement是在配置文件中定义的<select>元素的id.parameter是查询所需要的参数.rowBounds是用于分页的参数对象,使用该方法后会返回执行SQL语句查询结果的泛型对象的集合 |
void select(String statement,Object parameter,ResultHandler handler); | 查询方法.参数statement是在配置文件中定义的<select>元素的id.parameter是查询所需要的参数.ResultHandler 对象用于处理查询返回的复杂结果集,用于多表查询 |
int insert(String statement); | 插入方法,参数statement是在配置文件中定义的<insert>元素的id,使用该方法后会返回执行SQL语句所影响的行数 |
int insert(String statement,Object parameter); | 插入方法,参数statement是在配置文件中定义的<insert>元素的id,parameter是插入所需的参数,使用该方法后会返回执行SQL语句所影响的行数 |
int update(String statement); | 更新方法 ,参数statement是在配置文件中定义的<update>元素的id,使用该方法后会返回执行SQL语句所影响的行数 |
int update(String statement,Object parameter); | 更新方法 ,参数statement是在配置文件中定义的<update>元素的id,parameter是更新所需的参数,使用该方法后会返回执行SQL语句所影响的行数 |
int delete(String statement,); | 删除方法,参数statement是在配置文件中定义的<delete>元素的id,使用该方法后会返回执行SQL语句所影响的行数 |
int delete(String statement,Object parameter); | 删除方法,参数statement是在配置文件中定义的<delete>元素的id,parameter是删除所需的参数,使用该方法后会返回执行SQL语句所影响的行数 |
void commit(); | 提交事务的方法 |
void rollback(); | 回滚事务的方法 |
void close(); | 关闭SqlSession对象 |
<T> T getMapper(Class<T> type) | 该方法会返回Mapper接口的代理对象,该对象关联了SqlSession对象,开发人员可以使用该对象直接调用方法操作数据库.参数Type是Mapper 的接口类型 |
Connection getConnection(); | 获取JDBC数据库连接对象的方法 |
2.MyBatis的主要配置文件
2.1主要元素

注意:<configuration>的子元素必须按照图中由上到下的顺序进行配置,否则解析配置文件时会报错
2.2 <properties>元素
<properties>是一个配置属性的元素,该元素通常用于将内部的配置外在化,即通过外部的配置来动态地替换内部定义的属性
(1)创建db.properties的配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
(2)mybatis-config.xml中配置<properties>
<properties resource="db.properties"/>
(3)修改配置文件中的连接信息,具体如下:
<dataSource type="POOLED">
<!--数据库驱动-->
<property name="driver" value="${jdbc.driver}"/>
<!--连接数据库的url-->
<property name="url" value="${jdbc.url}"/>
<!--连接数据库的用户名-->
<property name="username" value="${jdbc.username}"/>
<!--连接数据库的密码-->
<property name="password" value="${jdbc.password}"/>
</dataSource>
2.3 <settings>元素
<settings>用于修改MyBatis运行时的行为,例如开启二级缓存、开启延时加载等
设置参数 | 描述 | 有效值 | 默认值 |
cacheEnabled | 该配置影响所有映射器中配置的缓存全局开关 | true|false | false |
lazyLoadingEnabled | 延迟加载的全局开关.开启时,所有关联对象都会延迟加载.特定关联关系中可以通过设置fetchType属性来覆盖该项的开关状态 | true|false | false |
aggressivelazyLoading | 关联对象属性的延迟加载开关.当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性都会按需加载 | true|false | true |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集 | true|false | true |
useColumnLabel | 使用列标签代替列名 | true|false | true |
useGeneratedKeys | 允许JDBC支持自动生成主键 | true|false | false |
autoMappingBehavior | 指定MyBatis应如何自动映射列到字段或属性.NONE表示取消自动映射;PARTIAL只会自动映射没有定义嵌套结果集映射的结果集;FULL会自动映射任意复杂的结果集(无论是否嵌套) | NONE|PARTIAL|FULL | PARTIAL |
defaultExecutorType | 配置默认的执行器.SIMPLE就是普通的执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 | SIMPLE|REUSE|BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库相应的秒数.当没有设置的时候,它取得就是驱动默认的时间 | 任何正整数 | 没有设置 |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camelcase)映射 | true|false | false |
jdbcTypeForNull | 当没有为参数提供特定的JDBC类型时,为空值指定JDBC类型. | NULL|VARCHAR|OTHER | OTHER |
2.4 <typeAliases>元素
<typeAliases>元素用于为配置文件中的Java类型设置别名,别名的设置与XML配置相关,其使用的意义在于减少全限定类名的冗余
当POJO类过多时,通过自动扫描包的形式自定义别名,示例如下:
<!--使用自动扫描包来定义别名-->
<typeAliases>
<package name="com.itcast.pojo">
</typeAliases>
需要注意的是,上述方式的别名只适用于没有使用注解的情况.如果在程序中使用了注解,则别名为其注解的值,具体如下:
@Alias(value="user")
public class User{
//User的属性和方法
...
}
别名 | 映射的类型 |
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
2.5 <typeHandler>元素
typeHandler的作用是将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType.
类型处理器 | Java类型 | JDBC类型 |
<typeHandler>元素就是用于在配置文件中注册自定义的类型处理器,它的使用方式有两种,如下
- 注册一个类的类型处理器
<typeHandlers>
<!--以单个类的形式配置-->
<typeHandler handler="com.itcast.type.CustomtypeHandler"/>
</typeHandlers>
- 注册一个包中所有的类型处理器
<typeHandlers>
<!--注册一个包中所有的typehandler,系统在启动时会自动扫描包下的所有文件-->
<package name="com.itcast.type"/>
</typeHandlers>
2.6 <objectFactory>元素
<objectFactory>的作用就是实例化目标类,既可以通过默认的构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化.
2.7 <plugins>元素
<plugins>元素的作用就是配置用户所开发的插件
2.8 <environments>元素
<environments>元素用于对环境进行配置.MyBatis的环境就是数据源的配置,即配置多种数据库.
<enviroments default="development">
<enviroment id="development">
<!--使用JDBC事务管理-->
<transactionManager type="JDBC">
<!--配置数据源-->
<dataSource type="POOLED">
<!--数据库驱动-->
<property name="driver" value="${jdbc.driver}"/>
<!--连接数据库的url-->
<property name="url" value="${jdbc.url}"/>
<!--连接数据库的用户名-->
<property name="username" value="${jdbc.username}"/>
<!--连接数据库的密码-->
<property name="password" value="${jdbc.password}"/>
</dataSource>
</enviroment>
</enviroments>
在MyBatis中,可以配置两种类型的事务管理器,分别是JDBC和MANAGED,关于这两个事务管理器的描述如下:
- JDBC:此配置直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务的作用域.
- MANAGED:此配置从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期,在默认情况下,它会关闭连接,但一些容器并不希望这样,为此可以将closeConnection属性设置为false来阻止它默认的关闭行为.
对于数据源的配置,MyBatis提供了UNPOOLED、POOLED和JNDI三种数据源类型,具体如下:
- UNPOOLED
配置此数据源类型后,在每次被请求时会打开和关闭连接。
属性 | 说明 |
driver | JDBC驱动的Java类的全限定类名 |
url | 数据库的URL地址 |
username | 登录数据库的用户名 |
password | 登录数据库的密码 |
defaultTransactionsolationLevel | 默认的连接事务隔离级别 |
- POOLED
此数据源利用"池"的概念将JDBC连接对象组织起来,避免了在创建新的连接实例时所需要初始化和认证的时间.
属性 | 说明 |
poolMaximumActiveConnections | 在任意时间正在使用的连接数量,默认值:10 |
poolMaximumldleConnections | 任意时间可能存在的空闲连接数 |
poolMaximumCheckoutTime | 在被强制返回前,池中连接被检出(checked out)时间,默认值:20000毫秒,即20秒 |
poolTimeToWait | 如果获取连接花费的时间较长,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直处于无提示的失败),默认值:20000毫秒,即20秒 |
poolPingQuery | 发送到数据库的侦测查询,用于检验连接是否处在正常工作秩序中,默认是"NO PING QUERY SET",这会导致多数数据库驱动失败时带有一定的错误消息 |
poolPingEnabled | 是否启用侦测查询.若开启,必须使用一个可执行的SQL语句设置poolPingQuery属性(最好是一个非常快的SQL),默认值:false |
poolPingConnectionsNotUsedFor | 配置poolPingQuery的使用频度.可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值:0(表示所有连接每一时刻都被侦测,只有poolPingEnabled的属性值为true时适用) |
- JNDI
此数据源可以在EJB或应用服务器等容器中使用.容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用.
属性 | 说明 |
initial_context | 此属性主要用于在initialcontext中寻找上下文(即initialcontext.lookup(initial_context))该属性为可选属性,在忽略时,data_source属性会直接从initialcontext中寻找 |
data_source | 此属性表示引用数据源实例位置的上下文的路径.如果提供了initial_context配置,那么程序会在其返回的上下文中进行查找;如果没有提供,则直接在initialcontext中查找. |
2.9 <mappers>元素
在配置文件中,<mappers>元素用于指定MyBatis映射文件的位置,一般可以使用以下4种方法引入映射器文件,具体如下:
- 使用类路径引入
<mappers>
<mappers resource="com/itcast/mapper/UserMapper.xml"/>
</mappers>
- 使用本地文件路径引入
<mappers>
<mappers url="file:///D:/com/itcast/mapper/UserMapper.xml"/>
</mappers>
- 使用接口类引入
<mappers>
<mapper class="com.itcast.mapper.UserMapper"/>
</mappers>
- 使用包名引入
<mappers>
<package name="com.itcast.mapper"/>
</mappers>
3. MyBatis的映射文件
3.1 主要元素
3.2 <select>元素
<select>元素用于映射查询语句,它的作用是从数据库中读取出数据,并组装数据给业务开发人员.
<select id="findCustomerById" parameterType="Integer"
resultType="com.itcast.po.Customer">
select * from t_customer where id=#{id}
</select>
上述语句中的唯一标识为findCustomerById,它接收一个Integer类型的参数,并返回一个Customer类型的对象.
属性 | 说明 |
id | 表示命名空间中的唯一标识符,常与命名空间组合起来使用.组合后如果不唯一,会抛异常 |
parameterType | 该属性表示传入SQL语句的参数类的全限定类名或者别名,它是一个可选属性,因为MyBatis可以通过TypeHandler推断出具体传入语句的参数,默认值是unset(依赖于驱动) |
resultType | 从SQL语句中返回的类型的类的全限定类名或者别名.如果是集合类型,那么返回的应该是集合可以包含的类型,而不是集合本身.返回时可以使用resultType或者resultMap之一 |
resultMap | 表示外部resultMap的命名引用.返回时可以使用resultType或者resultMap之一 |
flushCache | 表示在调用SQL语句之后,是否需要MyBatis青空之前查询的本地缓存和二级缓存.其值为布尔类型(true|false),默认值为false,如果设置为true,则任何时候只要SQL语句被调用,都会清空本地缓存和二级缓存. |
useCache | 用于控制二级缓存的开启和关闭.其值为布尔类型(true|false),默认值为true,表示将查询结果存入二级缓存中 |
timeout | 用于设置超时参数,单位为妙.超时将抛出异常 |
fetchSize | 获取记录的总条数设定,其默认值是unset(依赖于驱动) |
statementType | 用于设置MyBatis使用哪个JDBC的Statement工作,其值为STATEMENT、PREPARED(默认值)或CALLABLE,分别对应JDBC中的statement、PreparedStatement和CallableStatement |
resultSetType | 表示结果集的类型,其值可设置为FORWARD_ONLY,SCROLL_SENSITIVE或SCROLL_INSENSITIVE,默认值是unset(依赖于驱动) |
3.3 <insert> 元素
<insert> 元素用于映射插入语句,在执行完元素中定义的SQL语句后,会返回一个表示插入记录数的整数.
<insert
id="addCustomer"
parameterType="com.itcast.po.Customer"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
属性 | 说明 |
keyProperty | (仅对insert和update有用)作用是将插入或更新操作时的返回值赋值给PO类的某个属性,通常会设置为主键对应的属性.如果需要设置联合主键,可以在多个值之间用逗号隔开 |
keyColumn | (仅对insert和update有用)用于设置第几列是主键,当主键列不是表中的第一列时需要设置,在设置联合主键时,值可以用逗号隔开 |
useGeneratedKeys | (仅对insert和update有用)此属性会使MyBatis使用JDBC的getGeneratedKeys()方法来获取由数据库内部产生的主键,如MySQL和SQLServer等自动递增的字段,其默认值为false |
如果使用的数据库支持主键自动增长,那么可以通过keyProperty属性指定PO类的某个属性接收主键返回值(通常会设置到id属性上),然后将useGeneratedKeys的属性值设置为true,案例如下:
<insert id="addCustomer" parameterType="com.itcast.po.Customer"
keyProperty="id" useGeneratedKeys="true">
insert into t_customer(username,jobs,phone)
values(#{username},#{jobs},#{phone})
</insert>
使用上述配置执行插入后,会返回插入成功的行数,以及插入行的主键值,为了验证此配置,测试下:
@Test
public void addCustomerTest(){
//获取sqlsession
SqlSession sqlSession =MybatisUtils.getSession();
Customer customer =new Customer ();
customer.setUsername("rose");
customer.setJobs("student");
customer.setphone("18911961081");
int rows=sqlSession.insert("com.itcast.mapper."
+"CustomerMapper.addCustomer",customer);
//输出插入数据的主键id值
System.out.println(customer.getId());
if(rows>0){
System.out.println("成功插入了"+rows+"调数据");
}esle{
System.out.println("执行插入操作失败");
}
sqlSession.commit();
sqlSession.close();
}
}
如果使用的数据库不支持主键自动增长,或者支持增长的数据库取消了主键自增的规则时,也可以使用MyBatis提供的另一种方式来自定义生成主键
<insert id="insertCustomer" parameterType="com.itcast.po.Customer">
<selectKey keyProperty="id" resultType="Integer" order="BEFORE">
select if(max(id) is null,1,max(id)+1 as newId from t_customer)
</selectKey>
insert into t_customer(id,username,jobs,phone)
value(#{id},#{username},#{jobs},#{phone})
</insert>
在执行上述示例代码时,<selectKey>元素会首先运行,它会通过自定义的语句来设置数据表中主键(如果t_customer表中没有记录,则将id设置为1,否则就将id的最大值加1,来作为新的主键),然后再调用插入语句
<selectKey>元素在使用时可以设置以下几种属性
<selectKey
keyProperty="id"
resultType="Integer"
order="BEFORE"
statementType="PREPARED">
在上述<selectKey>几个属性中,order属性可以被设置为BEFORE或AFTER.如果设置为BEFORE,那么它会首先执行<selectKey>元素中的配置来设置主键,然后执行插入语句;如果设置为AFTER,那么它会先执行插入语句,然后执行<selectKey>元素中的配置内容.
3.4 <update>元素和<delete>元素
<update
id="updateCustomer"
parameterType="com.itcast.po.Customer"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="deleteCustomer"
parameterType="com.itcast.po.Customer"
flushCache="true"
statementType="PREPARED"
timeout="20">
<update>和<delete>元素在执行完之后,也会返回一个表示影响记录条数的整数
<!--更新信息-->
<update id="updateCustomer" parameterType="com.itcast.po.Customer">
update t_customer
set username=#{username},jobs=#{jobs},phone=#{phone}
where id=#{id}
</update>
<!--删除信息-->
<delete id="deleteCustomer" parameterType="Integer">
delete from t_customer where id=#{id}
</delete>
3.5 <sql>元素
<sql>元素的作用是定义可重用的SQL代码片段,然后在其它语句中引用这一代码片段.
<sql id="customerColumn">id,username,jobs,phone</sql>
这一代码片段可以包含在其它语句中使用,具体如下:
<select id="findCustomerById" parameterType="Integer"
resultType="com.itcast.po.Customer">
select <include refid="customerColumns"/>
from t_customer
where id=#{id}
</select>
在上述代码中,使用<include>元素的refid属性引用了自定义的代码片段,refid的属性值为自定义代码片段的id
<!--定义表的前缀名-->
<sql id="tablename">
${prefix}customer
</sql>
<!--定义要查询的表-->
<sql id="someinclude">
from
<include refid="${include_target}"/>
</sql>
<!--定义查询列-->
<sql id="customerColumns">
id,username,jobs,phone
</sql>
<!--根据id查询客户信息-->
<select id="findCustomerById" parameterType="Integer"
resultType="com.itcast.po.Customer">
select
<include refid="customerColumns"/>
<include refid="someinclude">
<property name="prefix" value="t_"/>
<property name="include_target" value="tablename"/>
</include>
where id=#{id}
</select>
上述代码中,定义了3个代码片段,分别为表的前缀名,要查询的表和需要查询的列.前2个代码片段中,分别获取了<include>子元素和<property>中的值,其中,第一个代码片段中的"${prefix}"会获取name为prefix的值"t_",获取后组成的表名为"t_customer";而第2个代码片段中的"${include_target}"会获取name为include_target的值"tablename",由于tablename为第1个SQL片段的id值,所以最后要查询的表为"t_customer"
3.6 <resultMap>元素
<resultMap>元素表示结果映射集,作用是定义映射规则、级联的更新以及定义类型转化器等
<resultMap>元素中包含了一些子元素,它的元素结构如下所示:
<!--resultMap的元素结构-->
<resultMap type="" id="">
<constructor> <!--类在实例化时,用来注入结果到构造方法中-->
<idArg/> <!--ID参数;标记结果作为ID-->
<arg/> <!--注入到构造方法的一个普通结果-->
</constructor>
<id/> <!--用于表示哪个列是主键-->
<result/> <!--注入到字段或JavaBean属性的普通结果-->
<association property=""/> <!--用于一对一关联-->
<collection property=""/ > <!--用于一对多关联-->
<discriminator javaType=""> <!--使用结果值来决定使用哪个结果映射-->
<case value=""/> <!--基于某些值的结果映射-->
</discriminator>
</resultMap>
<resultMap>元素的type属性表示需要映射的POJO,id属性是这个resultMap的唯一标识.它的子元素<constructor>用于配置构造方法(当一个POJO中未定义无参的构造方法时,就可以使用<constructor>元素进行配置)子元素<id>用于表示哪个列是主键,而<result>用于表示POJO和数据表中普通列的映射关系.<association>和<collection >用于处理多表时的关联关系,而<discriminator>元素主要用于处理一个单独的数据库查询返回很多不同数据类型届国际的情况
案例:数据库表中的列和需要返回的对象的属性可能不会完全一致,此时可以使用<resultMap>元素进行处理
(1)在数据库中,创建一个t_user表,并插入几条测试数据
USE mybatis;
CREATE TABLE t_user;
t_id INT PRIMARY KEY AUTO_INCREMENT,
t_name VARCHAR(50),
t_age INT
);
INSERT INTO t_user(t_name,t_age)VALUES('Lucy',25);
INSERT INTO t_user(t_name,t_age)VALUES('Lili',20);
INSERT INTO t_user(t_name,t_age)VALUES('Jim',20);
(2)在com.itcast.po包中,创建类User,在类中定义id,name和age属性,以及对应的getter/setter方法和toString()方法
(3)在com.itcast.mapper包下,创建映射文件UserMapper.xml,并在映射文件中编写映射查询语句
<mapper namespace="com.itcast.mapper.UserMapper">
<resultMap type="com.itcast.po.User" id="resultMap">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
<result property="age" column="t_age"/>
</resultMap>
<select id="findAllUser" resultMap="resultMap">
select * from t_user
</select>
</mapper>
<resultMap>的子元素<id><result>的property属性表示User类的属性名,column属性表示数据表t_user的列名<select>元素的resultMap属性表示引用上面定义的resultMap
(4)测试类,findAllUserTest()
@Test
public void findAllUserTest(){
//获取sqlsession
SqlSession sqlSession =MybatisUtils.getSession();
//SqlSession 执行映射文件中定义的SQL,并返回映射结果
List<User> list=
sqlSession .selectList("com.itcast.mapper.UserMapper.findAllUser");
for(User user:list){
System.out.println(user);
}
//关闭sqlSession
sqlSession.close();
}