2.mybatis-config基础

mybatis-config.xml(mybatis-config基础)

  1. 第一个MyBatis起步案例
  2. 第一个MyBatis起步案例解析
  3. 基于Java的配置方式说明

生日快乐!🎂🎂🎂🎉🎉🎉🎉🎉

总配置文件框架

1
2
3
4
5
6
7
<?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>

</configuration>

总配置文件常用标签解析

要想运行Mybatis,首先需要一个Mybatis总配置文件——mybatis-config.xml,通常这个配置文件会放在maven项目的Resources文件夹下面,这个配置文件的最基本内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.43.106:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="sujiewei"/>
</dataSource>
</environment>
</environments>

<mappers>
<mapper resource="tk/mybatis/simple/mapper/CountryMapper.xml"/>
</mappers>
</configuration>

首先要讲的第一部分:

1
2
3
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

熟悉xml的朋友都知道这个东东,这个东西是文档类型定义(DTD),可以如果感兴趣的同学可以点击这里将文件下载回来,用文本编辑软件打开查看里面的内容。

然后就是第二部分,\标签体的内容,对于每个mybatis-config.xml都需要一个\标签,在这个标签内,可以嵌套下面的标签,但下面的标签只能出现0次或者1次

  • \
  • \
  • \
  • \
  • \
  • \
  • \< reflectorFactory>
  • \< plugins>
  • \
  • \
  • \

\

<properties>用于指定一个键值对,也称<property><properties>标签可以指定两个属性:urlresource用于加载外部的properties文件,如:

1
<properties resource="config.properties"/>

这种所谓的properties文件,一般有下面的键值对的内容:

1
2
3
4
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://192.168.1.7:3306/mybatis
username=root
password=sujiewei

当然也可以在<properties>中指定新的键值对,但要注意,如果在外部文件和\中存在相同的标签,则会以外部文件中的为准。

1
2
3
4
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>

实际上,在创建SqlSessionFactory时也可以指定新的properties对象,并且这样的Properties拥有最高的优先级。

1
2
3
Properties props...;
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader,props);

想要引用<properties>标签的内容,可以使用${}引用变量名,像这样:

1
2
3
4
5
6
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>

如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:

  • 首先读取在 properties 元素体内指定的属性。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

MyBatis 3.4.2开始,你可以为占位符指定一个默认值。例如:

1
2
<property name="username" value="${username:root}"/>
<!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->

这个特性默认是关闭的。要启用这个特性,需要添加一个特定的属性来开启这个特性。例如:

1
2
3
4
<properties resource="org/mybatis/example/config.properties">
<!-- 启用默认值特性 -->
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
</properties>

如果值带有:的,还可以自定义分割符号,具体需要:

1
2
3
4
<properties resource="org/mybatis/example/config.properties">
<!-- 修改默认值的分隔符 -->
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/>
</properties>

那这样的话,分割符变成了?:,这个时候默认值就需要这样写:

1
2
<property name="username" value="${username?:root}"/>
<!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->

\

\ 标签中包含一些mybatis的设置选项 ,具体可以参考下面的图

火狐截图_2021-10-18T16-14-34.034Z (3).png)

\

类型别名可为 Java 类型设置一个缩写名字,它仅用于 XML 配置(config或者Mapper)。

1
2
3
4
5
6
7
8
9
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
<package name="domains"/>
</typeAliases>

这样配置的话使用resultType、或者parameterType属性中就可以使用别名,比如:

1
2
3
<select id="findUserByUsername" parameterType="Author" resultType="Blog">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>

还可以指定package,默认使用简易类名进行标识。

1
2
3
4
// domain.Country类
<typeAliases>
<package name="domain"/>
</typeAliases>

但是使用package的话,有一个不太好的地方是会产生冲突。

当两个包下存在同名的类的时候,需要额外给类指定别名,如:

1
2
3
4
5
6
// domain.Country
// bean.Country
<typeAliases>
<package name="domains"/>
<package name="beans"/>
</typeAliases>
1
The alias 'Country' is already mapped to the value 'domains.Country'.

解决方法:

使用注解@Alias分别给Country进行标记(大家当作是Country类就好,只为了做演示就不额外截图了)

image-20220426105943094

image-20220426105953989

然后Mapper.xml改成@Alias注解的名字:

1
2
3
<select id="findUserByUsername" parameterType="domainDept" resultType="beansDept">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>

当然,在Mybatis框架里面,有很多的已经内置好的别名,这些别名表参考下面:

别名 映射的类型
_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

\

现实中,我们的开发不可能只采用一套环境,往往是开发的一个数据库,测试的一个数据库这样。
一个SqlSessionFactory对应一套环境

因此我们的environments也可以配置多套:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="UNPOOLED">
<!-- localhost:3306/[数据库]-->
<!-- localhost:3306/mybatis-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.1.7:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="sujiewei"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>

default属性指定我们采用的环境的默认值。当然也可以在SqlSessionFactory中指定采用。但是需要注意,一套环境对应一个SqlSessionFactory

1
2
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, "development");
SqlSessionFactory factory2 = new SqlSessionFactoryBuilder().build(reader, "test", properties);

每个environments有两个子标签;

  • transactionManager:代表事务管理器
  • dataSource:代表数据源

数据库中的事务?一串原子性、同步的操作,要么不做,要么全做(举转账的例子)

transactionManager(事务管理器)

transactionManager里面可以填三种值:

  • JDBC:采用JDBC的事务提交和回滚设置。
  • MANAGED:让容器来管理事务的整个生命周期。
  • 自定义事务管理器类的全限定类名

自定义事务管理器需要实现两个接口TransactionFactoryTransaction

1
2
3
4
5
6
7
public interface TransactionFactory {
default void setProperties(Properties props) { // 从 3.5.2 开始,该方法为默认方法
// 空实现
}
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
1
2
3
4
5
6
7
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}

datasource

1
type="[UNPOOLED|POOLED|JNDI]",
UNPOOLED

每次请求都会打开关闭连接,如执行完一个SQL。该配置下只需要4种属性:

  • driver – 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。
  • url – 这是数据库的 JDBC URL 地址。
  • username – 登录数据库的用户名。
  • password – 登录数据库的密码。

可选的2种:

  • defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
  • defaultNetworkTimeout – 等待数据库操作完成的默认网络超时时间(单位:毫秒)。查看 java.sql.Connection#setNetworkTimeout() 的 API 文档以获取更多信息。
POOLED(连接池)

引入连接池,使用连接池的方式来进行数据库操作。数据交互非常频繁,具备UNPOOL的所有属性,在此基础上增加了:

  • poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10
  • poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
  • poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
  • poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
  • poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnectionspoolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
  • poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
  • poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
  • poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
JNDI(Java Naming and Directory Interface)
  • initial_context – 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。
  • data_source – 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。

除了这三种之外也可以使用外部的数据源,如:阿里的DruidC3P0,需要实现接口:DataSourceFactory

1
2
3
4
public interface DataSourceFactory {
void setProperties(Properties props);
DataSource getDataSource();
}

当然也可以实现相应的适配器类,如:

1
2
3
4
5
6
7
8
9
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {

public C3P0DataSourceFactory() {
this.dataSource = new ComboPooledDataSource();
}
}
  • UnpooledDataSourceFactory
  • PooledDataSourceFactory
  • JndiDataSourceFactory

例如:

1
2
3
4
5
6
<dataSource type="org.myproject.C3P0DataSourceFactory">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.1.7:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>

\

SQL语句映射配置文件。告诉Mybatis,我的SQL语句放在那里,你要去那里找这个SQL

mapper里面你可以写成路径的形式可以参考下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 使用相对于类路径的资源引用,有一个namespace东西,。不用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

<!-- 使用映射器接口实现类的完全限定类名,那么mapper文件和DAO接口要同名-->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

扫描的写法:

1
2
3
4
<!-- 写包名 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>

这几种写法有什么不同呢?

resourceurl属性:基于XMLMapper来找接口,注意namespace

class属性、package标签:基于接口来找XMLMapper,因此需要注意Mapper.xml文件和DAO接口要同包同文件名(测试之前先清空缓存)

这个路径的注意:

  • 如果使用XML方式配置建议采用resource属性,建议MapperDAO位于同一个包下
  • 如果使用注解方式配置建议采用class属性和package属性

注意要区分开来Mybatis总配置文件(配置Mybatis)和Mybatis映射文件(配置SQL语句)