引入Mybatis
Mybatis的快速入门
Mybatis的增删改查扩展功能说明
mapper映射的参数和结果
Mybatis复杂类型的结果映射
Mybatis基于注解的结果映射
Mybatis枚举类型处理和类型处理器
再谈动态SQL
在这篇文章中,我们将进入Mybatis配置的世界,了解Mybatis的基本配置方法,包括读取配置的方式、属性配置、环境配置、类型别名配置、类型处理器配置、映射器配置。准备好开启今天的神奇之旅了吗?
大家好,我是奇迹老李,一个专注于分享开发经验和基础教程的博主。欢迎来到我的频道,这里汇聚了汇集编程技巧、代码示例和技术教程,欢迎广大朋友们点赞评论提出意见,重要的是点击关注喔 ,期待在这里与你共同度过美好的时光️。今天要和大家分享的内容是Mybatis配置说明。做好准备,Let’s go
配置
mybatis项目读取配置的方式有两种,一种是通过读取xml配置文件的方式读取,另一种是通过java代码进行配置,这两中方式都是通过SqlSessionFactory这个类完成对mybatis的配置工作,这两种方式的样例代码如下:
xml配置文件示例(以下只是常用配置)
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="mysql-env.properties"/>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<typeAliases>
<package name="top.sunyog.common.entity"/>
typeAliases>
<typeHandlers>
<typeHandler handler="top.sunyog.mybatis.handler.LocalDateHandler"/>
typeHandlers>
<environments default="mysql">
<environment id="mysql">
<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>
<mappers>
<mapper resource="mapper/ApplicationMapper.xml"/>
mappers>
configuration>
读取xml配置
public class MybatisApp{
private static SqlSessionFactory sqlSessionFactory;
public static void startConfigFromXml(){
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
try (InputStream in = MybatisApp.class.getResourceAsStream("/mybatis-config.xml");
InputStreamReader reader=new InputStreamReader(in)) {
this.sqlSessionFactory = builder.build(reader);
} catch (IOException e) {
System.out.println("文件路径读取错误");
}
}
}
public class MybatisApp{
private static SqlSessionFactory sqlSessionFactory;
private static void startConfigFromApi(){
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setPassword("123456admin");
dataSource.setUrl("jdbc:mysql://db.sunyog.top:13306/sunyog_db");
dataSource.setUser("root");
JdbcTransactionFactory transFactory = new JdbcTransactionFactory();
Environment env = new Environment("env-2", transFactory,dataSource);
Configuration config = new Configuration();
config.setEnvironment(env);
config.getMapperRegistry().addMappers("top.sunyog.my.mapper");
config.getTypeAliasRegistry().registerAliases("top.sunyog.my.entity");
config.setMapUnderscoreToCamelCase(true);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
}
}
通过以上示例,并分析Mybatis代码可以看出,Mybatis通过org.apache.ibatis.session.Configuration
类来保存所有的配置,通过org.apache.ibatis.session.SqlSessionFactoryBuilder
类来 读取/构建 配置。xml和API的区别在于,API的方式直接通过Configuration
类创建DefaultSqlSessionFactory
类,而XML的方式是先读取XML文件构建Configuration
(这项工作在org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration
方法中),再创建DefaultSqlSessionFactory
。
xml配置文件标签和Configuration类属性的对应关系
名称 | 标签 | Configuration类属性名 | Configuration类属性类型 | 功能备注 |
---|---|---|---|---|
属性配置 |
|
variables | Properties | 自定义的k-v属性 |
环境配置 |
|
environment | Environment | 环境配置,如数据源 |
行为配置 |
|
各配置项不同 | 一般是boolean,有例外 | 用于配置mybatis的行为 |
类型别名 |
|
typeAliasRegistry | TypeAliasRegistry | 配置类型别名 |
类型处理器 |
|
typeHandlerRegistry | TypeHandlerRegistry | 配置类型转换器 |
映射配置 |
|
mapperRegistry | MapperRegistry | 配置mapper映射类/映射文件的位置 |
插件配置 |
|
interceptorChain | InterceptorChain | 配置mybatis插件 |
属性配置可以设置程序或后续配置中将要用到的k-v型参数。属性配置的方式有四种:
${uName:zhangsan}
的方式为没有指定的属性名设置默认值properties元素配置:
<configuration>
<properties>
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://db.sunyog.top:13306/sunyog_db"/>
<property name="username" value="root"/>
<property name="password" value="123456admin"/>
<property name="test-key" value="test-value-c"/>
properties>
configuration>
外部资源配置:
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://db.sunyog.top:13306/sunyog_db
username=root
password=123456admin
test-key=test-value-b
<configuration>
<properties resource="mysql-env.properties"/>
configuration>
远程资源的配置方式为:
test-key=test-value-a
<configuration>
<properties url="http://img.sunyog.top/config/mybatis-blog.properties"/>
configuration>
混合写法:
<properties resource="mysql-env.properties">
<property name="test-key" value="test-value-c"/>
properties>
如果混合使用两种方式,遇到同名配置时,Mybatis的处理优先级为:
C o n f i g u r a t i o n A P I > r e s o u r c e 或 u r l > p r o p e r t y 元素 Configuration API > resource或url > property元素 ConfigurationAPI>resource或url>property元素
以上的属性配置可以在mybatis的配置文件中通过 ${}
符号引用,亦可以在mybatis程序中通过Configuration
类使用,MybatisAPI引用示例:
public class MybatisConfigService extends MybatisService{
@Override
public void doService() {
SqlSessionFactory sqlSessionFactory = MybatisAppContext.getSqlSessionFactory();
Object v = sqlSessionFactory.getConfiguration().getVariables().get("test-key");
System.out.println(v);
}
}
//mybatis容器
public class MybatisAppContext {
private static SqlSessionFactory sqlSessionFactory = null;
static {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
try (InputStream in = MybatisApp.class.getResourceAsStream("/mybatis-config.xml");
InputStreamReader reader=new InputStreamReader(in)) {
sqlSessionFactory = builder.build(reader);
} catch (IOException e) {
System.out.println("文件路径读取错误");
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
//打印结果如下
test-value-b
环境配置主要用于配置数据源和事务处理器,Mybatis同时可以配置多个环境,但同一个SqlSessionFactory
实例只能有一个环境是可用的,通过
属性控制。
<configuration>
<environments default="mysql">
<environment id="mysql">
<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>
<environment id="mysql8">
<transactionManager type="MANAGED">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>
configuration>
测试多数据源应用
public class EnvConfigTest {
@Test
public void test2Env() throws IOException {
InputStream input = null;
InputStream input2=null;
try {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
input = EnvConfigTest.class.getResourceAsStream("/mybatis-config.xml");
SqlSessionFactory factory_1 = builder.build(input);
input2=EnvConfigTest.class.getResourceAsStream("/mybatis-config.xml");
SqlSessionFactory factory_2 = builder.build(input2, "mysql8");
TransactionFactory transaction_1 = factory_1.getConfiguration().getEnvironment().getTransactionFactory();
TransactionFactory transaction_2 = factory_2.getConfiguration().getEnvironment().getTransactionFactory();
System.out.println(transaction_1.getClass());
System.out.println(transaction_2.getClass());
} finally {
if (input !=null){
input.close();
}
if (input2!=null){
input2.close();
}
}
}
}
打印结果
class org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory
class org.apache.ibatis.transaction.managed.ManagedTransactionFactory
在 MyBatis 中有两种类型的事务管理器(也就是 type=“[JDBC|MANAGED]”):
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚功能,它依赖从数据源获得的连接来管理事务作用域。默认情况下,为了与某些驱动程序兼容,它在关闭连接时启用自动提交。然而,对于某些驱动程序来说,启用自动提交不仅是不必要的,而且是一个代价高昂的操作。因此,从 3.5.10 版本开始,你可以通过将 “skipSetAutoCommitOnClose” 属性设置为 “true” 来跳过这个步骤。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
<transactionManager type="JDBC">
<property name="skipSetAutoCommitOnClose" value="true"/>
transactionManager>
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
transactionManager>
除了以上两种内置的事务管理器之外,Mybatis还支持自定义事务管理器,需要实现 TransactionFactory
和 Transaction
两个接口。使用方式如下:
Transaction
和TransactionFactory
接口package top.sunyog.mybatis.trans;
import org.apache.ibatis.transaction.Transaction;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author Myste
* @since 2023/11/20 13:36
*/public class MyTransaction implements Transaction {
private Connection conn;
public MyTransaction(Connection conn) {
this.conn=conn;
}
@Override
public Connection getConnection() throws SQLException {
//设置不自动提交
conn.setAutoCommit(false);
return this.conn;
}
@Override
public void commit() throws SQLException {
//提交之前打印信息
System.out.println("自定义commit");
this.conn.commit();
}
@Override
public void rollback() throws SQLException {
this.conn.rollback();
}
@Override
public void close() throws SQLException {
this.conn.close();
}
@Override
public Integer getTimeout() throws SQLException {
return null;
}
}
package top.sunyog.mybatis.trans;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class MyTransactionFactory implements TransactionFactory {
@Override
public Transaction newTransaction(Connection conn) {
return new MyTransaction(conn);
}
@Override
public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
Transaction trans = null;
try {
Connection conn = dataSource.getConnection();
trans = new MyTransaction(conn);
return trans;
} catch (SQLException e) {
e.printStackTrace();
System.out.println("数据异常");
return null; }
}
}
<environments default="mysql">
<environment id="mysql">
<transactionManager type="top.sunyog.mybatis.trans.MyTransactionFactory">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>
private void testUpdateStatusScript(ApplicationRepository mapper){
AppTestEntity param = new AppTestEntity();
param.setId(1L);
param.setAppStatus("3");
int row = mapper.updateByScript(param);
System.out.println(row);
}
打印结果为:
1
自定义commit
查看数据库,确认状态已修改
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
有三种内建的数据源类型(也就是 type=“[UNPOOLED|POOLED|JNDI]”):
- UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
- POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
- JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。
以上三种数据源的可配置项如下
配置项 | 数据源 | 备注 | |
---|---|---|---|
driver | POOL和UNPOOL | 驱动类全名 | |
url | POOL和UNPOOL | JDBC的url地址 | |
username | POOL和UNPOOL | 数据库用户名 | |
password | POOL和UNPOOL | 数据库密码 | |
defaultTransactionIsolationLevel | POOL和UNPOOL | 数据库事务隔离级别 | |
defaultNetworkTimeout | POOL和UNPOOL | 数据库操作超时时间 | |
poolMaximumActiveConnections | POOL | 连接池中活动链接数量,默认10 | |
poolMaximumIdleConnections | POOL | 空闲连接数量 | |
poolMaximumCheckoutTime | POOL | 在被强制返回之前,池中连接被检出的时间,默认20秒 | |
poolTimeToWait | POOL | 如果获取连接花费时间超过这个数(默认20秒),连接池会打印状态日志并重新尝试获取一个连接 | |
poolMaximumLocalBadConnectionTolerance | POOL | 如果一个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnections 与 poolMaximumLocalBadConnectionTolerance 之和 |
|
poolPingQuery | POOL | 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET” | |
poolPingEnabled | POOL | 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false |
|
poolPingConnectionsNotUsedFor | POOL | 配置 poolPingQuery 的频率。(默认值为0,仅当 poolPingEnabled 为 true 时适用) |
关于数据源的配置,前四项是必填项,其他配置都有默认值。实际应用中,可根据服务器硬件配置修改个别配置。
除去以上三种数据源之外,还可以使用第三方数据源,如:c3p0
和druid
两种数据源比较常见,其中druid
为alibaba提供,国内常用。
通过配置类型别名,可以在xml映射文件中使用别名来简化resultType
和parameterType
属性,如
<configuration>
<typeAliases>
<package name="top.sunyog.common.entity"/>
typeAliases>
configuration>
<select id="queryById" resultType="AppTestEntity">
<include refid="query_column"/> where id=#{id} limit 0,1
select>
注意:可以为整个包内的所有类型设置别名,也可以为一个类设置单独的别名。两种方式的写法如下
<typeAlias type="top.sunyog.common.entity.AppTestEntity" alias="app"/>
<package name="top.sunyog.common.entity"/>
另外,mybatis内置了一部分常见的类型别名,可以在 org.apache.ibatis.type.TypeAliasRegistry
这个类的构造方法中查看
public class TypeAliasRegistry {
...
public TypeAliasRegistry() {
registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("char", Character.class);
registerAlias("character", Character.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("char[]", Character[].class);
registerAlias("character[]", Character[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_char", char.class);
registerAlias("_character", char.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_char[]", char[].class);
registerAlias("_character[]", char[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
registerAlias("ResultSet", ResultSet.class);
}
}
在获取到数据库查询结果时,mybatis会通过类型处理器将查询结果转换为对应的java类型,mybatis中内置了很多类型处理器,除此之外,如果内置的类型处理器不满足业务需要,还可以通过实现org.apache.ibatis.type.TypeHandler
接口或继承org.apache.ibatis.type.BaseTypeHandler
类的方式自定义类型处理器。
mybatis内置的类型处理器可以通过这个链接查看 https://mybatis.org/mybatis-3/zh/configuration.html#typeHandlers
自定义类型处理器详见枚举类型处理和类型处理器一文
mybatis中的映射器包括mapper接口和mapper文件两种,mybatis程序在启动时需要读取映射器到内存中备用,所以需要指定mapper接口或mapper文件的位置。有以下几种形式
<mappers>
<mapper resource="mapper/ApplicationMapper.xml"/>
mappers>
<mapper class="top.sunyog.mybatis.mapper.AppAnnoMapper"/>
<package name="top.sunyog.mybatis.mapper"/>
<mapper url="file:///app/app_demo/mappers/ApplicationMapper.xml"/>
这里需要注意:如果通过指定mapper接口来配置映射器,需要保证接口的包路径名称和xml文件的文件夹路径名称一致,否则会因为两者对应不上而报错,除非没有xml映射文件(通过注解或代码的形式指定sql语句)。
Mybatis中提供了丰富的配置项,需要我们在日常开发过程中慢慢感受配置对Mybatis行为的影响。本文我们主要学习了关于Mybatis配置的入门知识,包括配置的两种方式(XML和API)、两种配置方式之间的对应关系以及几类简单的配置,它们是
联系方式
邮箱:[email protected]❗版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问奇迹老李的博客首页