大纲
- 配置
- 代码
在实际开发中,我们往往会将开发环境分成:开发、测试、线上等环境。这些环境的数据源不一样,比如开发环境就不能访问线上环境,否则极容易出现线上数据污染等问题。Mybatis通过多环境配置分开定义来解决这个问题,即我们可以在Mybatis的配置文件中定义多个环境的信息。
配置
下面的配置在environments项下分出了两个environment:
- development。用于开发环境。开发环境连接的数据库是testdb,这在url中体现出来。
- production。用于生产环境。生产环境连接的数据库是db。
environments的default属性定义了默认选择哪个environment。这样如果我们代码没有指定环境名,则会使用这个默认的environment配置来配置环境。
<?xml version="1.0" encoding="UTF-8" ?>
<!-- mybatis-config-multi-env.xml -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testdb?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="fangliang"/>
</dataSource>
</environment>
<environment id="production">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="fangliang"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mybatis/mapper/AllTypeMapper.xml"/>
</mappers>
</configuration>
在上例中,dataSource下除了url不同外(因为要连接不同数据库),数据库其他信息(比如用户名和密码等)都是一样的。这样相同数据写多次,很容易在后续维护中出现问题,比如不小心的修改导致数据不一致的问题。
为了避免这类问题,我们可以将相同的字段放到properties字段下,然后在使用的地方使用${PropertyName}的形式引用。
<?xml version="1.0" encoding="UTF-8" ?>
<!-- mybatis-config-multi-env-1.xml -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties>
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="fangliang"/>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="jdbc:mysql://localhost:3306/testdb?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="production">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="jdbc:mysql://localhost:3306/db?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mybatis/mapper/AllTypeMapper.xml"/>
</mappers>
</configuration>
代码
Mybatis的代码核心流程是:
- 构建SqlSessionFactoryBuilder
- 使用1返回的对象构建SqlSessionFactory
- 使用2返回的对象构建SqlSession
SqlSessionFactoryBuilder是不区分生产环境或者开发环境的,而SqlSessionFactory是区分的,即给build传递环境变量名。下面代码传递的是production,这样后续创建的session就是连着生产环境。
InputStream in = null;
try {
in = Resources.getResourceAsStream("mybatis/config/mybatis-config-multi-env.xml");
} catch (IOException e) {
throw new RuntimeException(e);
}
SqlSessionFactory sqlSFLocal = new SqlSessionFactoryBuilder().build(in, "production");
完整代码如下
@Test
void testMultiEnv() {
ArrayList<String> configs = new ArrayList<>(
Arrays.asList("mybatis/config/mybatis-config-multi-env.xml",
"mybatis/config/mybatis-config-multi-env-1.xml")
);
for (String config : configs) {
InputStream in = null;
try {
in = Resources.getResourceAsStream(config);
} catch (IOException e) {
throw new RuntimeException(e);
}
SqlSessionFactory sqlSFLocal = new SqlSessionFactoryBuilder().build(in, "production");
List<AllType> all = null;
try (SqlSession s = sqlSFLocal.openSession()) {
all = s.selectList("org.example.mapper.AllTypeMapper.findAll");
} catch (Exception e) {
System.out.println(e.getMessage());
}
for (AllType a : Objects.requireNonNull(all)) {
System.out.println(a.getInfo_int());
}
}
}
代码样例见:https://github.com/f304646673/mybatis_demo.git