第7章 MyBatis的核心配置
学习目标
● 了解MyBatis核心对象的作用
● 熟悉MyBatis配置文件中各个元素的作用
● 掌握MyBatis映射文件中常用元素的使用
7.1 MyBatis的核心对象
SqlSessionFactory
它是单个数据库映射关系经过编译后的内存镜像,其主要作用是创建SqlSession
SqlSessionFactoryBuilder则可以通过XML配置文件或一个预先定义好的Configuration实例构建出SqlSessionFactory的实例
// 读取配置文件 InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
// 根据配置文件构建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
线程安全,它一旦被创建,在整个应用执行期间都会存在,多次地创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽,通常每一个数据库都会只对应一个SqlSessionFactory,使用单例模式
SqlSession
它是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作。包含了数据库中所有执行SQL操作的方法,由于其底层封装了JDBC连接,所以可以直接使用其实例来执行已映射的SQL语句。
每一个线程都应该有一个自己的SqlSession实例,并且该实例是不能被共享的。
线程不安全,使用范围最好在一次请求或一个方法中,绝不能将其放在一个类的静态字段、实例字段或任何类型的管理范围(如Servlet的HttpSession)中使用,使用完需及时关闭,通常可以将其放在finally块中关闭
· <T> T selectOne(String statement);返回执行SQL语句查询结果的一条泛型对象。
· <T> T selectOne(String statement, Object parameter);
· <E> List<E> selectList(String statement);
· <E> List<E> selectList(String statement, Object parameter);
· <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);rowBounds是用于分页的参数对象
· void select(String statement, Object parameter,ResultHandler handler);ResultHandler对象用于处理查询返回的复杂结果集,通常用于多表查询
· int insert(String statement);返回执行SQL语句所影响的行数
· int insert(String statement, Object parameter);
· int update(String statement);返回执行SQL语句所影响的行数
· int update(String statement, Object parameter);
· int delete(String statement);返回执行SQL语句所影响的行数。
· int delete(String statement, Object parameter);
· void commit();
· void rollback();
· void close();
· <T> T getMapper(Class<T> type);
· Connection getConnection();获取JDBC数据库连接对象的方法。
工具类
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
// 初始化sqlsessionfactory对象
static {
try{
// 使用mybatis提供的resource类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
// 构建sqlsession工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
// 获取sqlsession对象的静态方法
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
7.2 配置文件
7.2.1 主要元素
<configuration>元素根元素

<configuration>的子元素必须按照图7-1中由上到下的顺序进行配置,否则MyBatis在解析XML配置文件的时候会报错。
7.2.2 <properties>元素
将内部的配置外在化,即通过外部的配置来动态地替换内部定义的属性。
db.properties配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/spring?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=root
mybatis-config.xm
<properties resource="db.properties" />
<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>
动态替换,为配置提供了诸多灵活的选择。还可以通过配置<properties>元素的子元素<property>,以及通过方法参数传递的方式来获取属性值。实际开发中,使用properties配置文件来配置属性值最常用。
7.2.3 <settings>元素
主要用于改变MyBatis运行时的行为,例如开启二级缓存、开启延迟加载等

<! -- 设置 -->
<settings>
<setting name="cacheEnabled" value="true" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="multipleResultSetsEnabled" value="true" />
<setting name="useColumnLabel" value="true" />
<setting name="useGeneratedKeys" value="false" />
<setting name="autoMappingBehavior" value="PARTIAL" />
...
</settings>
7.2.4 <typeAliases>元素
为配置文件中的Java类型设置一个简短的名字,即设置别名
<! -- 定义别名 -->
<typeAliases>
<typeAlias alias="user" type="com.itheima.po.User"/>
</typeAliases>
如果省略alias属性,MyBatis会默认将类名首字母小写后的名称作为别名
当POJO类过多时,还可以通过自动扫描包的形式自定义别名
<! -- 使用自动扫描包来定义别名 -->
<typeAliases>
<package name="com.itheima.po"/>
</typeAliases>
上述方式的别名只适用于没有使用注解的情况。如果在程序中使用了注解,则别名为其注解的值
@Alias(value = "user")
public class User {
//User的属性和方法
}
MyBatis框架还默认为许多常见的Java类型(如数值、字符串、日期和集合等)提供了相应的类型别名

别名不区分大小写,所以在使用时要注意重复定义的覆盖问题。
7.2.5 <typeHandler>元素
将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType。

还可以通过自定义的方式对类型处理器进行扩展(自定义类型处理器可以通过实现TypeHandler接口或者继承BaseTypeHandle类来定义。
1.注册一个类的类型处理器
<typeHandlers>
<! -- 以单个类的形式配置 -->
<typeHandler handler="com.itheima.type.CustomtypeHandler" />
</typeHandlers>
2.注册一个包中所有的类型处理器
<typeHandlers>
<! -- 注册一个包中所有的typeHandler,系统在启动时会自动扫描包下的所有文件,并把它们作为类型处理器。-->
<package name="com.itheima.type" />
</typeHandlers>
7.2.6 <objectFactory>元素
MyBatis框架每次创建结果对象的新实例时,都会使用一个对象工厂(ObjectFactory)的实例来完成。MyBatis中默认的ObjectFactory(由org.apache.ibatis.reflection.factory.DefaultObjectFactory来提供服务的)的作用就是实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化。
自定义:
(1)自定义一个对象工厂。实现ObjectFactory接口,或者继承DefaultObjectFactory类
// 自定义工厂类
public class MyObjectFactory extends DefaultObjectFactory {
private static final long serialVersionUID = -4114845625429965832L;
public <T> T create(Class<T> type) {
return super.create(type);
}
public <T> T create(Class<T> type, List<Class<? >> constructorArgTypes, List<Object> constructorArgs) {
return super.create(type, constructorArgTypes, constructorArgs);
}
public void setProperties(Properties properties) {
super.setProperties(properties);
}
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
}
(2)在配置文件中使用<objectFactory>元素配置自定义的ObjectFactory
<objectFactory type="com.itheima.factory.MyObjectFactory">
<property name="name" value="MyObjectFactory"/>
</objectFactory>
7.2.7 <plugins>元素
插件。
7.2.8 <environments>元素
实际上就是数据源的配置,我们可以通过<environments>元素配置多种数据源,即配置多种数据库。
<!--default属性,该属性用于指定默认的环境ID-->
<environments default="development">
<environment id="development">
<! -- 使用JDBC事务管理 -->
<transactionManager type="JDBC" />
<! -- 配置数据源 -->
<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>
在MyBatis中,可以配置两种类型的事务管理器,分别是JDBC和MANAGED。
· JDBC:此配置直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务的作用域。
· MANAGED:此配置从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。在默认情况下,它会关闭连接,但一些容器并不希望这样,为此可以将closeConnection属性设置为false来阻止它默认的关闭行为。
如果项目中使用的是Spring+ MyBatis,则没有必要在MyBatis中配置事务管理器,因为实际开发中,会使用Spring自带的管理器来实现事务管理。
对于数据源的配置,MyBatis框架提供了UNPOOLED、POOLED和JNDI三种数据源类型。
· UNPOOLED
在每次被请求时会打开和关闭连接,适合没有性能要求的简单应用程序。

· POOLED
此数据源利用“池”的概念将JDBC连接对象组织起来,避免了在创建新的连接实例时所需要初始化和认证的时间。这种方式使得并发Web应用可以快速地响应请求,是当前流行的处理方式。

· JNDI
可以在EJB或应用服务器等容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

7.2.9 <mappers>元素
指定MyBatis映射文件的位置
1.使用类路径引入
<mappers> <mapper resource="com/itheima/mapper/UserMapper.xml"/> </mappers>
2.使用本地文件路径引入
<mappers> <mapper url="file:///D:/com/itheima/mapper/UserMapper.xml"/> </mappers>
3.使用接口类引入
<mappers> <mapper class="com.itheima.mapper.UserMapper"/> </mappers>
4.使用包名引入
<mappers> <package name="com.itheima.mapper"/> </mappers>
7.3 映射文件
7.3.1 主要元素

7.3.2 <select>元素
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer">
select * from t_customer where id = #{id}
</select>

7.3.3 <insert>元素
<insert
id="addCustomer"
parameterType="com.itheima.po.Customer"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">

如果使用的数据库支持主键自动增长(如MySQL),那么可以通过keyProperty属性指定PO类的某个属性接收主键返回值(通常会设置到id属性上),然后将useGeneratedKeys的属性值设置为true
<insert id="addCustomer" parameterType="com.itheima.po.Customer"
keyProperty="id" useGeneratedKeys="true" >
insert into t_customer(username, jobs, phone)
values(#{username}, #{jobs}, #{phone})
</insert>
如果使用的数据库不支持主键自动增长(如Oracle),或者支持增长的数据库取消了主键自增的规则时,也可以使用MyBatis提供的另一种方式来自定义生成主键,具体配置示例如下。
<insert id="insertCustomer" parameterType="com.itheima.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)
values(#{id}, #{username}, #{jobs}, #{phone})
</insert>
<selectKey>元素会首先运行,它会通过自定义的语句来设置数据表中的主键(如果t_customer表中没有记录,则将id设置为1,否则就将id的最大值加1,来作为新的主键),然后再调用插入语句。
<selectKey keyProperty="id" resultType="Integer" order="BEFORE" statementType="PREPARED">
order属性可以被设置为BEFORE或AFTER。如果设置为BEFORE,那么它会首先执行<selectKey>元素中的配置来设置主键,然后执行插入语句;如果设置为AFTER,那么它会先执行插入语句,然后执行<selectKey>元素中的配置内容。
7.3.4 <update>元素和<delete>元素
<update
id="updateCustomer"
parameterType="com.itheima.po.Customer"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="deleteCustomer"
parameterType="com.itheima.po.Customer"
flushCache="true"
statementType="PREPARED"
timeout="20">
<! -- 更新信息 -->
<update id="updateCustomer" parameterType="com.itheima.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>
7.3.5 <sql>元素
定义可重用的SQL代码片段,然后在其他语句中引用这一代码片段
<sql id="customerColumns">id, username, jobs, phone</sql>
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> select <include refid="customerColumns"/> from t_customer where id = #{id} </select>
<! --定义表的前缀名 -->
<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.itheima.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>
7.3.6 <resultMap>元素
定义映射规则、级联的更新以及定义类型转化器等。
<! --resultMap的元素结构 -->
<resultMap type="" id="">
<constructor> <! -- 类在实例化时,用来注入结果到构造方法中-->
<idArg/> <! -- ID参数;标记结果作为ID-->
<arg/> <! -- 注入到构造方法的一个普通结果-->
</constructor>
<id/> <! -- 用于表示哪个列是主键-->
<result/> <! -- 注入到字段或JavaBean属性的普通结果-->
<association property="" /> <! -- 用于一对一关联 -->
<collection property="" /> <! -- 用于一对多关联 -->
处理一个单独的数据库查询返回很多不同数据类型结果集的情况
<discriminator javaType=""> <! -- 使用结果值来决定使用哪个结果映射-->
<case value="" /> <! -- 基于某些值的结果映射 -->
</discriminator>
</resultMap>
案例
1.建表
2.实体类并且实现getter、setter方法和toString
3.mapper
<mapper namespace="com.itheima.po.User">
<resultMap id="resultMap" type="com.itheima.po.User">
<id property="id" column="t_id"/>
<id property="name" column="t_name"/>
<id property="age" column="t_age"/>
</resultMap>
<select id="findAllUser" resultMap="resultMap">
select *
from t_user;
</select>
</mapper>
4.在配置文件mybatis-config.xml中,引入UserMapper.xml
<!-- 配置Mapper的位置-->
<mappers>
<mapper resource="com/itheima/mapper/UserMapper.xml"/>
</mappers>
5.测试类
@Test
public void findAllUserTest() {
SqlSession sqlSession = MybatisUtils.getSession();
// InputStream inputStream = Resources.getResourceAsStream("mybatis-config1.xml");
// SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("com.itheima.po.User.findAllUser");
for(User user : list){
System.out.println(user);
}
sqlSession.close();
}
Mapped Statements collection does not contain value for com.itheima.mapper.UserMapper.findAllUser
sqlSession.selectList("mapper.namespace + mapper.方法")
Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the connection string near ';useSSL=false&serverTimezone=UTC'.
由于使用的是properties配置数据库源,需要把&修改回&
getResourceAsReader和getResourceAsStremer的区别?
【思考题】
1.请简述MyBatis核心对象SqlSessionFactory的获取方式。
Resource调用getResourceasStream方法,传入根据mybatis-config.xml配置文件,获取到的值作为 new一个sqlsessionfactorybuilder对象build的方法参数,创建出sqlsessionfactory
2.请简述MyBatis映射文件中的主要元素及其作用。
主要元素
<configuration>
<enviroment>配置运行环境
<mapper>
<select>
……
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?