SSMSSM
首页
  • 我的博客
  • 我的Github
首页
  • 我的博客
  • 我的Github
  • Java反射技术
  • 动态代理模式
  • 设计模式简介
  • 责任链模式
  • 观察者模式
  • 工厂模式与抽象工厂模式
  • 建造者模式
  • Web开发历史
  • Mybatis核心组件
  • Mybatis的反射
  • Mybatis配置

Mybatis配置

  • 概述
  • 1.properties
    • property 子元素
    • properties 文件
    • 程序代码传递
  • 2.settings
  • 3.typeAliases
    • 系统已定义
    • 自定义
  • 4.typeHandler
    • 系统已定义
    • 自定义
  • 5.objectFactory
  • 6.plugins
  • 7.environments
  • 8.databaseIdProvider
  • 9.mappers

概述

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <properties/> <!-- 属性 -->
    <settings/><!-- 设置 -->
    <typeAliases/><!-- 别名 -->
	<typeHandlers/><!-- 类型转换 -->
    <objectFactory/><!-- 对象工厂 -->
	<plugins/><!--插件-->
    
    <environments default="development"><!-- 数据库环境 -->
        <environment id="development"><!-- 环境XX -->
            <transactionManager type="JDBC"/><!-- 事务管理器 -->
            <dataSource type="POOLED"/><!-- 数据源 -->
        </environment>
    </environments>
    
    <databaseIdProvider/><!-- 数据库厂商标识 -->
    <mappers/><!-- 映射器 -->
</configuration>

    MyBatis 配置项的顺序不能颠倒。如果颠倒了它们的顺序,那么 MyBatis 启动阶段就会发生异常导致程序无法运行。

1.properties

properties属性可以给系统配置一些运行参数。有三种方式使用它:

  • property 子元素
  • properties 文件(推荐)
  • 程序代码传递

它们的优先级是:程序代码传递 > properties文件 > property 子元素,推荐使用properties文件。

最初数据库配置方式如下:

<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/ssm"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </dataSource>
    </environment>
</environments>

默认是固定写死的,可以用下面三种方式将其提取出来。

property 子元素

<?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>
    
    <properties>
        <property name="database.driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="database.url" value="jdbc:mysql://localhost:3306/ssm"/>
        <property name="database.username" value="root"/>
        <property name="database.password" value="123456"/>
    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${database.driver}"/>
                <property name="url" value="${database.url}"/>
                <property name="username" value="${database.username}"/>
                <property name="password" value="${database.password}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

如果属性参数有成百上千个,这种写法不合适,推荐properties文件。

properties 文件

jdbc.properties

database.driver=com.mysql.cj.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/ssm
database.username=root
database.password=123456
<?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>

    <properties resource="jdbc.properties"/>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${database.driver}"/>
                <property name="url" value="${database.url}"/>
                <property name="username" value="${database.username}"/>
                <property name="password" value="${database.password}"/>
            </dataSource>
        </environment>
    </environments>

</configuration>

程序代码传递

这里jdbc.properties文件里,连接数据库的用户名与密码是经过运维人员加密过的,对开发人员保密。那么需要将其解密后重新设置属性值。

InputStream in = Resources.getResourceAsStream("jdbc.properties");
Properties props = new Properties();
props.load(in);
String username = props.getProperty("database.username");
String password = props.getProperty("database.password");
// 解密用户和密码,并在属性中重置
props.put("database.username", CodeUtils.decode(username));
props.put("database.password", CodeUtils.decode(password));
inputStream = Resources.getResourceAsStream(resource);
// 使用程序传递的方式覆盖原有的properties属性参数
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, props);

因其优先级最高,所以会覆盖jdbc.properties里设置的默认值。

2.settings

    settings 是 MyBatis 最复杂的配置,它能深刻影响 MyBatis 底层的运行,但是在大部分情况下使用默认值便可以运行。有时候需要修改一 些常用的规则,比如自动映射、驼峰命名映射、级联规则、 是否启动缓存、执行器(Executor)类型等。

常用配置项如下表所示:

配置项默认值可选值 / 类型作用说明
cacheEnabledtruetrue / false全局开启或关闭缓存(包括一级、二级缓存)
lazyLoadingEnabledfalsetrue / false是否启用懒加载(延迟加载)
multipleResultSetsEnabledtruetrue / false允许返回多个结果集(适用于存储过程)
useColumnLabeltruetrue / false是否使用列标签而不是列名作为字段映射的依据(一般用 AS 时需要为 true)
useGeneratedKeysfalsetrue / false是否允许 JDBC 支持自动生成主键(例如 MySQL 的自增主键)
autoMappingBehaviorPARTIALNONE / PARTIAL / FULL自动映射未知列到字段的行为(FULL 会更激进,NONE 禁用自动映射)
autoMappingUnknownColumnBehaviorNONENONE / WARNING / FAILING未知列映射行为(NONE 忽略,WARNING 打日志,FAILING 抛异常)
defaultExecutorTypeSIMPLESIMPLE / REUSE / BATCH设置默认执行器类型,BATCH 用于批量操作
mapUnderscoreToCamelCasefalsetrue / false是否自动将下划线命名映射为驼峰命名(如 user_name -> userName)
localCacheScopeSESSIONSESSION / STATEMENT本地缓存作用域(SESSION 共享一个会话缓存,STATEMENT 每次查询都清空)
jdbcTypeForNullOTHERJDBC 类型为 null 值指定默认 JDBC 类型(如 VARCHAR, NULL, OTHER)
logImpl未配置STDOUT_LOGGING, LOG4J, LOG4J2, SLF4J, COMMONS_LOGGING, NO_LOGGING指定使用的日志框架
callSettersOnNullsfalsetrue / false为 null 值也调用 setter 方法(默认不调用)
returnInstanceForEmptyRowfalsetrue / false查询结果为空时是否返回空对象而不是 null(影响结果映射)
shrinkWhitespacesInSqlfalsetrue / false是否压缩 SQL 中多余的空白字符(保持格式统一)

3.typeAliases

    由于类的全限定名称很长,需要大量使用的时候,总写那么长的名称不方便。在 MyBatis 中允许定义一个简写来代表这个类,这就是别名,别名分为系统定义别名和自定义别名。

    MyBatis 中别名不区分大小写。

系统已定义

别名对应 Java 类型是否支持数组
_bytebyte✅
_charchar✅
_doubledouble✅
_floatfloat✅
_intint✅
_longlong✅
_shortshort✅
_booleanboolean✅
stringjava.lang.String✅
bytejava.lang.Byte✅
charjava.lang.Character✅
doublejava.lang.Double✅
floatjava.lang.Float✅
intjava.lang.Integer✅
longjava.lang.Long✅
shortjava.lang.Short✅
booleanjava.lang.Boolean✅
datejava.util.Date✅
decimaljava.math.BigDecimal✅
bigintegerjava.math.BigInteger✅
objectjava.lang.Object✅
mapjava.util.Map❌
hashmapjava.util.HashMap❌
listjava.util.List❌
arraylistjava.util.ArrayList❌
collectionjava.util.Collection❌
iteratorjava.util.Iterator❌

上述别名是在org.apache.ibatis.type.TypeAliasRegistry类中定义的,如下代码所示:

package org.apache.ibatis.type;

//import

public class TypeAliasRegistry {
    private final Map<String, Class<?>> TYPE_ALIASES = new HashMap();

    public TypeAliasRegistry() {
        this.registerAlias("string", String.class);
        this.registerAlias("byte", Byte.class);
        this.registerAlias("long", Long.class);
        this.registerAlias("short", Short.class);
        this.registerAlias("int", Integer.class);
        this.registerAlias("integer", Integer.class);
        this.registerAlias("double", Double.class);
        this.registerAlias("float", Float.class);
        this.registerAlias("boolean", Boolean.class);
        this.registerAlias("byte[]", Byte[].class);
        this.registerAlias("long[]", Long[].class);
        this.registerAlias("short[]", Short[].class);
        this.registerAlias("int[]", Integer[].class);
        this.registerAlias("integer[]", Integer[].class);
        this.registerAlias("double[]", Double[].class);
        this.registerAlias("float[]", Float[].class);
        this.registerAlias("boolean[]", Boolean[].class);
        this.registerAlias("_byte", Byte.TYPE);
        this.registerAlias("_long", Long.TYPE);
        this.registerAlias("_short", Short.TYPE);
        this.registerAlias("_int", Integer.TYPE);
        this.registerAlias("_integer", Integer.TYPE);
        this.registerAlias("_double", Double.TYPE);
        this.registerAlias("_float", Float.TYPE);
        this.registerAlias("_boolean", Boolean.TYPE);
        this.registerAlias("_byte[]", byte[].class);
        this.registerAlias("_long[]", long[].class);
        this.registerAlias("_short[]", short[].class);
        this.registerAlias("_int[]", int[].class);
        this.registerAlias("_integer[]", int[].class);
        this.registerAlias("_double[]", double[].class);
        this.registerAlias("_float[]", float[].class);
        this.registerAlias("_boolean[]", boolean[].class);
        this.registerAlias("date", Date.class);
        this.registerAlias("decimal", BigDecimal.class);
        this.registerAlias("bigdecimal", BigDecimal.class);
        this.registerAlias("biginteger", BigInteger.class);
        this.registerAlias("object", Object.class);
        this.registerAlias("date[]", Date[].class);
        this.registerAlias("decimal[]", BigDecimal[].class);
        this.registerAlias("bigdecimal[]", BigDecimal[].class);
        this.registerAlias("biginteger[]", BigInteger[].class);
        this.registerAlias("object[]", Object[].class);
        this.registerAlias("map", Map.class);
        this.registerAlias("hashmap", HashMap.class);
        this.registerAlias("list", List.class);
        this.registerAlias("arraylist", ArrayList.class);
        this.registerAlias("collection", Collection.class);
        this.registerAlias("iterator", Iterator.class);
        this.registerAlias("ResultSet", ResultSet.class);
    }

    public <T> Class<T> resolveAlias(String string) {
        //...
    }

    public void registerAliases(String packageName) {
        this.registerAliases(packageName, Object.class);
    }

    public void registerAliases(String packageName, Class<?> superType) {
        //...
    }

    public void registerAlias(Class<?> type) {
        //...
    }

    public void registerAlias(String alias, Class<?> value) {
        //...
    }

    public void registerAlias(String alias, String value) {
        //...
    }

    public Map<String, Class<?>> getTypeAliases() {
        return Collections.unmodifiableMap(this.TYPE_ALIASES);
    }
}

而org.apache.ibatis.session.Configuration类中也对一些常用配置项配置了别名,如下代码所示:

package org.apache.ibatis.session;

//import

public class Configuration {
    //variables...

    public Configuration(Environment environment) {
        this();
        this.environment = environment;
    }

    public Configuration() {
        //initial...
        
        this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
        this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
        this.typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
        this.typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
        this.typeAliasRegistry.registerAlias("LRU", LruCache.class);
        this.typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
        this.typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
        this.typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
        this.typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
        this.typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
        this.typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
        this.typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
        this.typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
        this.typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
        this.typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
        this.typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
        this.typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
        this.typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
       	
        //other...
    }

}

自定义

我们构建SqlSessionFactory时,有两种方式:XML配置与纯代码,所以这里自定义别名有两种方式。

XML配置

1.单个列明

<typeAliases>
    <typeAlias alias="role" type="com.learn.ssm.chapter4.pojo.Role"/>
    <typeAlias alias="user" type="com.learn.ssm.chapter4.pojo.User" />
</typeAliases>

2.一整个包

<typeAliases>
    <package name="com.learn.ssm.chapter4.pojo" />
</typeAliases>

    这样 MyBatis 将扫描这个包里面的类,将其第1个字母变为小写作为其别名,比如 Role 的别名会变为 role,而 User 的别名会变为 user 。

    这样可能出现重名的情况,比如不同的包下有同名的类User,此时可以通过Mybatis提供的@Alias注解来区分:

package com.learn.ssm.chapter3.pojo;
@Alias("user3")
public Class User { 
    //...
}

纯代码

DataSource dataSource = new PooledDataSource(...);
TransactionFactory transactionFactory = new JdbcTransactionFactory();

Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);

// 注册别名
configuration.getTypeAliasRegistry().registerAlias("myUser", com.xxx.User.class);

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(configuration);

4.typeHandler

TypeHandler 是 MyBatis 用来在 Java 类型 和 JDBC 类型之间进行转换 的处理器。

当 MyBatis 和数据库交互时,它需要把:

  • Java 对象 → 数据库字段(写入)
  • 数据库字段 → Java 对象(读取)

这个转换过程,就由 TypeHandler 来完成。 TypeHandler 也分系统定义与自定义。

Java 类型

系统已定义

TypeHandler 类名对应 Java 类型对应 JDBC 类型
BooleanTypeHandlerBoolean / booleanBOOLEAN / BIT
ByteTypeHandlerByte / byteTINYINT
ShortTypeHandlerShort / shortSMALLINT
IntegerTypeHandlerInteger / intINTEGER
LongTypeHandlerLong / longBIGINT
FloatTypeHandlerFloat / floatFLOAT
DoubleTypeHandlerDouble / doubleDOUBLE
BigDecimalTypeHandlerBigDecimalDECIMAL, NUMERIC
StringTypeHandlerStringVARCHAR, CHAR, TEXT
DateTypeHandlerjava.util.DateTIMESTAMP, DATE, TIME
TimeOnlyTypeHandlerjava.sql.TimeTIME
DateOnlyTypeHandlerjava.sql.DateDATE
TimestampTypeHandlerjava.sql.TimestampTIMESTAMP
ClobTypeHandlerClob, StringCLOB
BlobTypeHandlerBlob, byte[]BLOB
ByteArrayTypeHandlerbyte[]BINARY, VARBINARY
EnumTypeHandler<E extends Enum<E>>Enum 类型VARCHAR, INT(可自定义)
ObjectTypeHandler任意 Object(默认处理器)自动判断或兜底

上述类型处理器是在org.apache.ibatis.type.TypeHandlerRegistry类中定义的,如下代码所示:

public final class TypeHandlerRegistry {
    private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap(JdbcType.class);
    private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap();
    private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
    private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap();

    public TypeHandlerRegistry() {
        this.register((Class)Boolean.class, new BooleanTypeHandler());
        this.register((Class)Boolean.TYPE, new BooleanTypeHandler());
        this.register(JdbcType.BOOLEAN, new BooleanTypeHandler());
        this.register(JdbcType.BIT, new BooleanTypeHandler());
        this.register((Class)Byte.class, new ByteTypeHandler());
        this.register((Class)Byte.TYPE, new ByteTypeHandler());
        this.register(JdbcType.TINYINT, new ByteTypeHandler());
        this.register((Class)Short.class, new ShortTypeHandler());
        this.register((Class)Short.TYPE, new ShortTypeHandler());
        this.register(JdbcType.SMALLINT, new ShortTypeHandler());
        this.register((Class)Integer.class, new IntegerTypeHandler());
        this.register((Class)Integer.TYPE, new IntegerTypeHandler());
        this.register(JdbcType.INTEGER, new IntegerTypeHandler());
        this.register((Class)Long.class, new LongTypeHandler());
        this.register((Class)Long.TYPE, new LongTypeHandler());
        this.register((Class)Float.class, new FloatTypeHandler());
        this.register((Class)Float.TYPE, new FloatTypeHandler());
        this.register(JdbcType.FLOAT, new FloatTypeHandler());
        this.register((Class)Double.class, new DoubleTypeHandler());
        this.register((Class)Double.TYPE, new DoubleTypeHandler());
        this.register(JdbcType.DOUBLE, new DoubleTypeHandler());
        this.register((Class)Reader.class, new ClobReaderTypeHandler());
        this.register((Class)String.class, new StringTypeHandler());
        this.register(String.class, JdbcType.CHAR, new StringTypeHandler());
        this.register(String.class, JdbcType.CLOB, new ClobTypeHandler());
        this.register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
        this.register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
        this.register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
        this.register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
        this.register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
        this.register(JdbcType.CHAR, new StringTypeHandler());
        this.register(JdbcType.VARCHAR, new StringTypeHandler());
        this.register(JdbcType.CLOB, new ClobTypeHandler());
        this.register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
        this.register(JdbcType.NVARCHAR, new NStringTypeHandler());
        this.register(JdbcType.NCHAR, new NStringTypeHandler());
        this.register(JdbcType.NCLOB, new NClobTypeHandler());
        this.register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
        this.register(JdbcType.ARRAY, new ArrayTypeHandler());
        this.register((Class)BigInteger.class, new BigIntegerTypeHandler());
        this.register(JdbcType.BIGINT, new LongTypeHandler());
        this.register((Class)BigDecimal.class, new BigDecimalTypeHandler());
        this.register(JdbcType.REAL, new BigDecimalTypeHandler());
        this.register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
        this.register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
        this.register((Class)InputStream.class, new BlobInputStreamTypeHandler());
        this.register((Class)Byte[].class, new ByteObjectArrayTypeHandler());
        this.register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
        this.register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
        this.register((Class)byte[].class, new ByteArrayTypeHandler());
        this.register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
        this.register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
        this.register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
        this.register(JdbcType.BLOB, new BlobTypeHandler());
        this.register(Object.class, this.UNKNOWN_TYPE_HANDLER);
        this.register(Object.class, JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER);
        this.register(JdbcType.OTHER, this.UNKNOWN_TYPE_HANDLER);
        this.register((Class)Date.class, new DateTypeHandler());
        this.register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
        this.register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
        this.register(JdbcType.TIMESTAMP, new DateTypeHandler());
        this.register(JdbcType.DATE, new DateOnlyTypeHandler());
        this.register(JdbcType.TIME, new TimeOnlyTypeHandler());
        this.register((Class)java.sql.Date.class, new SqlDateTypeHandler());
        this.register((Class)Time.class, new SqlTimeTypeHandler());
        this.register((Class)Timestamp.class, new SqlTimestampTypeHandler());

        try {
            this.register("java.time.Instant", "org.apache.ibatis.type.InstantTypeHandler");
            this.register("java.time.LocalDateTime", "org.apache.ibatis.type.LocalDateTimeTypeHandler");
            this.register("java.time.LocalDate", "org.apache.ibatis.type.LocalDateTypeHandler");
            this.register("java.time.LocalTime", "org.apache.ibatis.type.LocalTimeTypeHandler");
            this.register("java.time.OffsetDateTime", "org.apache.ibatis.type.OffsetDateTimeTypeHandler");
            this.register("java.time.OffsetTime", "org.apache.ibatis.type.OffsetTimeTypeHandler");
            this.register("java.time.ZonedDateTime", "org.apache.ibatis.type.ZonedDateTimeTypeHandler");
            this.register("java.time.Month", "org.apache.ibatis.type.MonthTypeHandler");
            this.register("java.time.Year", "org.apache.ibatis.type.YearTypeHandler");
        } catch (ClassNotFoundException var2) {
        }

        this.register((Class)Character.class, new CharacterTypeHandler());
        this.register((Class)Character.TYPE, new CharacterTypeHandler());
    }
}

自定义

自定义TypeHandler

SexEnum

package com.learn.ssm.chapter4.enumeration;

public enum SexEnum{
    MALE(1, "男"),
    FEMALE(2, "女");

    private int id;
    private String name;

    SexEnum(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static SexEnum getSexById(int id) {
        for (SexEnum sex: SexEnum.values()) {
            if(sex.getId() == id) {
                return sex;
            }
        }
        return null;
    }
}

SexEnumTypeHandler

package com.learn.ssm.chapter4.typeHandler;

import com.learn.ssm.chapter4.enumeration.SexEnum;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SexEnumTypeHandler implements TypeHandler<SexEnum> {

    // 把 Java 类型的参数转换成 JDBC 类型,设置到 PreparedStatement 中
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i, parameter.getId());
    }

    // 从 ResultSet 中取出某列,根据列名,转换成 Java 类型
    @Override
    public SexEnum getResult(ResultSet resultSet, String columnName) throws SQLException {
        int id = resultSet.getInt(columnName);
        return SexEnum.getSexById(id);
    }

    // 从 ResultSet 中取出某列,根据列索引,转换成 Java 类型
    @Override
    public SexEnum getResult(ResultSet resultSet, int columnIndex) throws SQLException {
        int id = resultSet.getInt(columnIndex);
        return SexEnum.getSexById(id);
    }

    // 从 CallableStatement 中取出某列(通常是存储过程的输出参数),转换成 Java 类型
    @Override
    public SexEnum getResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
        int id = callableStatement.getInt(columnIndex);
        return SexEnum.getSexById(id);
    }
}

这里重写的四个方法中,setParameter方法是将java类型转jdbc类型,剩下的三个getResult是将jdbc类型转java类型。

方法名方向说明
setParameter(...)Java → JDBC插入/更新 数据时,把 Java 对象转成数据库字段
getResult(...) (×3)JDBC → Java查询结果 时,把数据库字段转成 Java 类型

POJO

package com.learn.ssm.chapter4.pojo;

import com.learn.ssm.chapter4.enumeration.SexEnum;

public class User {

    private Long id;
    private String username;
    private String password;
    private SexEnum sex;

    //getter and setter
}

Interface UserMapper

package com.learn.ssm.chapter4.mapper;

import com.learn.ssm.chapter4.pojo.User;

public interface UserMapper {
    public int insertUser(User user);
    public int deleteUser(Long id);
    public int updateUser(User user);
    public User getUser(Long id);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learn.ssm.chapter4.mapper.UserMapper">

    <insert id="insertUser" parameterType="user">
        INSERT INTO t_user (id, username, password, sex)
        VALUES (#{id}, #{username}, #{password}, #{sex, typeHandler=com.learn.ssm.chapter4.typeHandler.SexEnumTypeHandler})
    </insert>

    <delete id="deleteUser" parameterType="long">
        DELETE FROM t_user WHERE id = #{id}
    </delete>

    <update id="updateUser" parameterType="user">
        UPDATE t_user
        SET username = #{username},
        password = #{password},
        sex = #{sex, typeHandler=com.learn.ssm.chapter4.typeHandler.SexEnumTypeHandler}
        WHERE id = #{id}
    </update>

    <select id="getUser" parameterType="long" resultType="user">
        SELECT id, username, password, sex FROM t_user
        WHERE id = #{id}
    </select>

</mapper>

别名、类型处理器、映射器等需要在配置文件中引入:

mybatis-config.xml

<?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>
    
    <properties resource="jdbc.properties"/>

    <!-- 别名 -->
    <typeAliases>
        <typeAlias alias="role" type="com.learn.ssm.chapter3.pojo.Role"/>
        <typeAlias alias="user" type="com.learn.ssm.chapter4.pojo.User" />
    </typeAliases>

    <!-- 类型处理器 -->
    <typeHandlers>
        <typeHandler handler="com.learn.ssm.chapter4.typeHandler.SexEnumTypeHandler"
                     javaType="com.learn.ssm.chapter4.enumeration.SexEnum"/>
    </typeHandlers>

    <!-- 数据库环境 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${database.driver}"/>
                <property name="url" value="${database.url}"/>
                <property name="username" value="${database.username}"/>
                <property name="password" value="${database.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 映射文件 -->
    <mappers>
        <mapper resource="com/learn/ssm/chapter3/mapper/RoleMapper.xml"/>
        <mapper resource="com/learn/ssm/chapter4/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

SqlSessionFactoryUtils

package com.learn.ssm.chapter4.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class SqlSessionFactoryUtils {

    private final static Class<SqlSessionFactoryUtils> LOCK = SqlSessionFactoryUtils.class;

    // 构造函数
    private SqlSessionFactoryUtils(){}

    // 单例模式
    private static SqlSessionFactory sqlSessionFactory = null;
    public static SqlSessionFactory getSqlSessionFactory() {
        synchronized (LOCK) {
            if(sqlSessionFactory != null) {
                return sqlSessionFactory;
            }

            // XML配置方式 实例化SqlSessionFactory
            String resource = "mybatis-config.xml";
            InputStream inputStream;
            try {
                inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sqlSessionFactory;
    }

    public static SqlSession openSqlSession() {
        if(sqlSessionFactory == null) {
            getSqlSessionFactory();
        }
        return sqlSessionFactory.openSession();
    }

}

Main

package com.learn.ssm.chapter4.main;

import com.learn.ssm.chapter4.enumeration.SexEnum;
import com.learn.ssm.chapter4.mapper.UserMapper;
import com.learn.ssm.chapter4.pojo.User;
import com.learn.ssm.chapter4.utils.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

public class Main {
    public static void main(String[] args) {
        testUser();
    }

    public static void testUser() {
        Logger logger = Logger.getLogger(Main.class);
        SqlSession sqlSession = null;
        try {
            sqlSession = SqlSessionFactoryUtils.openSqlSession();
            UserMapper UserMapper = sqlSession.getMapper(UserMapper.class);

            User user = new User();
            user.setId(1L);
            user.setUsername("IU");
            user.setPassword("123456");
            user.setSex(SexEnum.MALE);
            int num = UserMapper.insertUser(user);
            logger.info(num);//1

            User user1 = UserMapper.getUser(1L);
            logger.info(user1);//com.learn.ssm.chapter4.pojo.User@625abb97
            logger.info(user1.getSex());//MALE

            user1.setUsername("Alice");
            num = UserMapper.updateUser(user1);
            logger.info(num);//1

            num = UserMapper.deleteUser(1L);
            logger.info(num);//1

            //提交事务
            sqlSession.commit();
        } catch (Exception e) {
            if(sqlSession != null) {
                sqlSession.rollback();
            }
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}

5.objectFactory

6.plugins

7.environments

8.databaseIdProvider

9.mappers

最近更新:: 2025/10/17 07:52
Contributors: fireworks99
Prev
Mybatis的反射