- 目录
mybatis(二)xml配置方式详细说明
详细说明几个比较重要的mybatis配置项
2.1、使用properties配置属性
在日常工作中,我们可能需要将一些配置信息写在一个单独的properties配置文件中便于管理,mybatis对此进行了很好的支持
2.1.1、引入外部properties文件或在properties标签内定义属性
- 创建db.properties文件
url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
driverClass=com.mysql.cj.jdbc.Driver
username=root
pwd=Test#123345
- 在mybatis主配置文件导入db.properties
<?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="db.properties">
<property name="username" value="root"/>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射扫描 -->
<mappers>
<mapper class="com.szm.mapper.UserMapper"/>
</mappers>
</configuration>
2.1.1.1、如果一个属性在不只一个地方进行了配置,加载顺序(官方解释)如下:
-
首先读取在 properties 元素体内指定的属性。
-
然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
-
最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
总结:如果存在同名属性,resource指向的文件中的属性值将会覆盖元素体内指定的属性值。
2.2、类型别名(typeAliases)
2.2.1、对象别名
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 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="db.properties">
<property name="username" value="root"/>
</properties>
<!-- 配置别名-->
<typeAliases>
<typeAlias alias="user" type="com.szm.pojo.User"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射扫描 -->
<mappers>
<mapper class="com.szm.mapper.UserMapper"/>
</mappers>
</configuration>
在指定了别名之后,就可以在mapper的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.szm.mapper.UserMapper">
<select id="selectUser" resultType="user">
select * from user
</select>
</mapper>
2.2.2、指定包名,自动生成别名
- typeAliases也可以指定一个包名,例如:
<typeAliases>
<package name="com.szm.pojo"/>
</typeAliases>
在指定了一个包名之后,会使用类名的首字母小写的非限定类名来作为它的别名,例如:
//这里的话就会用user来作为别名
public class User {
private int id;
private String name;
private String pwd;
}
也可以使用注解结合typeAliases指定包名来实现定义别名。例如:
<typeAliases>
<!--指定包路径 -->
<package name="com.szm.pojo"/>
</typeAliases>
//使用注解指定别名
@Alias("user")
public class User {
private int id;
private String name;
private String pwd;
}
2.2.3内置的java类型别名
别名 | 类型 |
---|---|
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 |
2.3 、类型处理器(typeHandlers)
2.3.1、何为类型处理器:
- 官方解释:
MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。
- 来个冗长的类型处理器对应的表吧:
类处理器名称 | Java类型 | jdbc类型 |
---|---|---|
BooleanTypeHandler | java.lang.Boolean , boolean | 数据库兼容的 BOOLEAN |
ByteTypeHandler | java.lang.Byte , byte | 数据库兼容的 NUMERIC 或 BYTE |
ShortTypeHandler | java.lang.Short , short | 数据库兼容的 NUMERIC 或 SMALLINT |
IntegerTypeHandler | java.lang.Integer , int | 数据库兼容的 NUMERIC 或 INTEGER |
LongTypeHandler | java.lang.Long , long | 数据库兼容的 NUMERIC 或 BIGINT |
FloatTypeHandler | java.lang.Float , float | 数据库兼容的 NUMERIC 或 FLOAT |
DoubleTypeHandler | java.lang.Double , double | 数据库兼容的 NUMERIC 或 DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | 数据库兼容的 NUMERIC 或 DECIMAL |
StringTypeHandler | java.lang.String | CHAR , VARCHAR |
ClobReaderTypeHandler | java.io.Reader | - |
ClobTypeHandler | java.lang.String | CLOB , LONGVARCHAR |
NStringTypeHandler | java.lang.String | NVARCHAR , NCHAR |
NClobTypeHandler | java.lang.String | NCLOB |
BlobInputStreamTypeHandler | java.io.InputStream | - |
ByteArrayTypeHandler | byte[] | 数据库兼容的字节流类型 |
BlobTypeHandler | byte[] | BLOB , LONGVARBINARY |
DateTypeHandler | java.util.Date | TIMESTAMP |
DateOnlyTypeHandler | java.util.Date | DATE |
TimeOnlyTypeHandler | java.util.Date | TIME |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP |
SqlDateTypeHandler | java.sql.Date | DATE |
SqlTimeTypeHandler | java.sql.Time | TIME |
ObjectTypeHandler | Any | OTHER 或未指定类型 |
EnumTypeHandler | Enumeration Type | VARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值) |
EnumOrdinalTypeHandler | Enumeration Type | 任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。 |
SqlxmlTypeHandler | java.lang.String | SQLXML |
InstantTypeHandler | java.time.Instant | TIMESTAMP |
LocalDateTimeTypeHandler | java.time.LocalDateTime | TIMESTAMP |
LocalDateTypeHandler | java.time.LocalDate | DATE |
LocalTimeTypeHandler | java.time.LocalTime | TIME |
OffsetDateTimeTypeHandler | java.time.OffsetDateTime | TIMESTAMP |
OffsetTimeTypeHandler | java.time.OffsetTime | TIME |
ZonedDateTimeTypeHandler | java.time.ZonedDateTime | TIMESTAMP |
YearTypeHandler | java.time.Year | INTEGER |
MonthTypeHandler | java.time.Month | INTEGER |
YearMonthTypeHandler | java.time.YearMonth | VARCHAR 或 LONGVARCHAR |
2.3.2、测试自定义的类型处理器(官方例子)
自定义类型处理器,将getNullableResult获取结果返回值写一个固定的值测试是否生效
package com.szm.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return "myTypeHandlerString-getNullableResult(ResultSet rs, String columnName)";
//return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return "myTypeHandlerString-getNullableResult(ResultSet rs, int columnIndex)";
// return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return "myTypeHandlerString-getNullableResult(CallableStatement cs, int columnIndex)";
// return cs.getString(columnIndex);
}
}
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="db.properties">
<property name="username" value="root"/>
</properties>
<!-- 配置别名-->
<typeAliases>
<typeAlias alias="user" type="com.szm.pojo.User"/>
</typeAliases>
<!--配置自定义类型处理器 -->
<typeHandlers>
<typeHandler handler="com.szm.handler.MyTypeHandler"/>
</typeHandlers>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射扫描 -->
<mappers>
<mapper class="com.szm.mapper.UserMapper"/>
</mappers>
</configuration>
测试代码:
@Test
public void test() throws IOException {
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectUserLike("user");
users.stream().forEach((e)->{
System.out.println(e);
});
sqlSession.close();
}
结果可以看到所有的String类型参数结果都是我们定义的固定返回值:
User(id=1, name=myTypeHandlerString-getNullableResult(ResultSet rs, String columnName), pwd=myTypeHandlerString-getNullableResult(ResultSet rs, String columnName))
User(id=2, name=myTypeHandlerString-getNullableResult(ResultSet rs, String columnName), pwd=myTypeHandlerString-getNullableResult(ResultSet rs, String columnName))
User(id=3, name=myTypeHandlerString-getNullableResult(ResultSet rs, String columnName), pwd=myTypeHandlerString-getNullableResult(ResultSet rs, String columnName))
2.4、对象工厂(objectFactory)
2.4.1、官方解释
每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现。
2.4.2、代码实现
-
在User对象中新增一个数据库中没有的扩展字段
package com.szm.pojo; import lombok.AllArgsConstructor; import lombok.Data; @Data public class User { private int id; private String name; private String pwd; //查询结果没有这个字段 private String extendField; }
-
自定义对象工厂
package com.szm.factory;
import com.szm.pojo.User;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import java.util.List;
import java.util.UUID;
public class MyObjectFactory extends DefaultObjectFactory {
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
T t = super.create(type, constructorArgTypes, constructorArgs);
if (User.class.isAssignableFrom(type)) {
User user = (User) t;
//给这个对象的ExtendField赋值一个随机值
user.setExtendField(UUID.randomUUID().toString());
}
return t;
}
}
- 配置自定义对象工厂
<?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="db.properties">
<property name="username" value="root"/>
</properties>
<!-- 配置别名-->
<typeAliases>
<typeAlias alias="user" type="com.szm.pojo.User"/>
</typeAliases>
<!--配置自定义类型处理器 -->
<typeHandlers>
<typeHandler handler="com.szm.handler.MyTypeHandler"/>
</typeHandlers>
<!-- 配置自定义对象工厂-->
<objectFactory type="com.szm.factory.MyObjectFactory"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射扫描 -->
<mappers>
<mapper class="com.szm.mapper.UserMapper"/>
</mappers>
</configuration>
- 测试
@Test
public void test() throws IOException {
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectUserLike("user");
users.stream().forEach((e)->{
System.out.println(e);
});
sqlSession.close();
}
- 结果
User(id=1, name=user1, pwd=pwd1, nickname=123)
User(id=2, name=user2, pwd=pwd2, nickname=123)
User(id=3, name=user3, pwd=pwd3, nickname=123)
2.5、映射器(mappers)
2.5.1、xml配置映射器
- 配置文件在java包路径下
<!-- 使用相对于类路径的资源引用 ,如果主配置文件在resource下,则应该如下使用-->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</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>
- 直接指定mapper接口位置(这种方式你必须在接口使用注解方式定义好要执行的sql语句)
<!--接口全路径 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 包路径,将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>