1. JDBC属性文件
在资源文件夹下新建db.properties文件,其内容如下
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3307/mybatis
username=root
password=root
修改conf.xml的内容
首先引入资源文件db.properties
<properties resource="db.properties"/>
然后配置数据库信息
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
这样的话,只需要在资源文件里修改数据库信息
2. Mybatis全局参数
可以在conf.xml里添加全局参数,初学者不建议使用
<configuration>
<properties resource="db.properties"/>
<settings>
<setting name="cacheEnabled" value="false"/>
<setting name="lazyLoadingEnabled" value="false"/>
</settings>
<environments default="development">
......
</environments>
<mappers>
......
</mappers>
</configuration>
3. 别名
在Mapper-interface.xml里,返回值类型为com.santiago.maven.Student
,我们可以为其定义别名,使得代码简洁。
在conf.xml里,可加入如下配置
- 定义别名时,不考虑大小写
定义别名有两种方式:1. 定义单个别名;2. 批量定义别名
- 定义单个别名
<typeAliases>
<typeAlias type="com.santiago.maven.Student" alias="Student"/>
</typeAliases>
- 批量定义别名
将包的名称引入,别名默认为该包中类的名字(不考虑大小写,不带包名),如下所示
<typeAliases>
<package name="com.santiago.maven"/>
</typeAliases>
Mybatis自带的别名,不用定义就可以使用
4. 类型处理器
想象这么两个场景。
- 在类中用String类型修饰性别(男:male;女:female),在数据库中用int类型来修饰男女(男:1;女:0)。那么这两者怎么映射?
- 在类中编号用id表示,而在数据库中编号用no表示。那么这两者怎么映射?
这就需要用到类型处理器,Mybatis有很多内置的类型处理器,如果内置的不够用,还可以自定义处理器
4.1 内置类型处理器
类型处理器 | 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 |
JapaneseDateTypeHandler | java.time.chrono.JapaneseDate | DATE |
4.2 自定义类型处理器
自定义类型处理器需要实现TypeHandler接口,通过阅读源码,发现TypeHandler接口有一个实现类BaseTypeHandler。
因此创建自定义类型处理器有两种方法:
1. 实现TypeHandler接口
2. 继承BaseTypeHandler
我们使用第二种较为简单的方法
使用自定义类型转换器的步骤
4.2.1 首先修改Student类和数据库,添加sex属性,在数据库中,设置stuno为主键
4.2.2 新建一个转换器类StringAndInt.java,继承自BaseTypeHandler
public class StringAndInt extends BaseTypeHandler<String> {
}
其中泛型类型根据自己使用的javaType修改,并重写方法,接下来分别介绍重写的四个方法
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String parameter, JdbcType jdbcType) throws SQLException {
if("female".equals(parameter)){
preparedStatement.setInt(i,0);
}else if("male".equals(parameter)){
preparedStatement.setInt(i, 1);
}
}
该方法完成从java到DB这个方向的类型转换,其中参数:
- PreparedStatement preparedStatement:PreparedStatement对象
- int i:PreparedStatement对象操作参数的位置
- String parameter:java类型
- JdbcType jdbcType:jdbc数据库类型
其余三种方式均是从DB往java这个方向转换
根据列名拿返回结果
@Override
public String getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
int sex = resultSet.getInt(columnName);
return sex == 1 ? "male" : "female";
}
根据下标拿返回结果
@Override
public String getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
int sex = resultSet.getInt(columnIndex);
return sex == 1 ? "male" : "female";
}
根据存储过程拿返回结果
@Override
public String getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
int sex = callableStatement.getInt(columnIndex);
return sex == 1 ? "male" : "female";
}
4.2.3 在配置文件配置类型处理器
在conf.xml里添加如下内容
<typeHandlers>
<typeHandler handler="com.santiago.convertor.StringAndInt" javaType="String" jdbcType="INTEGER"/>
</typeHandlers>
编写Mapper-interface.xml映射文件 显然用到resultMap
注意:主键与非主键的表达方式不同,例如,stuno
为主键,则用id
标签,stuName
为非主键,则用result
标签
<select id="queryStudentByStuNoWithConvertor" resultMap="SR" parameterType="int">
select * from student where stuno = #{stuno}
</select>
<resultMap id="SR" type="Student">
<id property="stuNo" column="stuno"/>
<result property="stuName" column="stuname"/>
<result property="stuAge" column="stuage"/>
<result property="gradeName" column="gradename"/>
<result property="sex" column="sex" javaType="String" jdbcType="INTEGER"/>
</resultMap>
插入和更新操作不要忘了修改,需要注意的地方如下
<update id="updateStudentByStuNo" parameterType="Student">
update student set stuname = #{stuName}, stuage = #{stuAge}, gradename = #{gradeName}, sex = #{sex, javaType=String, jdbcType=INTEGER} where stuno = #{stuNo}
</update>
<insert id="addStudent" parameterType="Student">
insert into student(stuno,stuname,stuage,gradename,sex) values(#{stuNo},#{stuName},#{stuAge},#{gradeName},sex = #{sex, javaType=String, jdbcType=INTEGER})
</insert>
4.2.4 测试
不使用类型转换器的情况
使用类型转换器的情况
注意:在xml文件中,jdbcType要写成大写INTEGER,否则报错,我也不知道为什么
对于第二种场景,类中属性名和表中字段名不能够自动匹配,也需要用到resultMap
,以查询单个学生为例
<select id="queryStudentByStuNo" resultMap="updateStudent" parameterType="int">
select * from student where stuno = #{stuno}
</select>
<resultMap id="updateStudent" type="Student">
<id property="id" column="stuno"/>
<result property="stuName" column="stuname"/>
<result property="stuAge" column="stuage"/>
<result property="gradeName" column="gradename"/>
<result property="sex" column="sex" javaType="String" jdbcType="INTEGER"/>
</resultMap>
只是把属性名properrty
和列名column
进行了修改,使其匹配。如果属性名和列名一致,不需要添加resultMap