1、配置文件的结构
配置文件包含控制MyBatis功能的重要信息,是MyBatis实现功能的重要保证。在开发过程中,当需要更改MyBatis 的配置信息时,只需更改配置文件中的相关元素及属性即可。
MyBatis规定了其配置文件的层次结构,具体如下所示。
需要注意的是,MyBatis配置文件的元素在文件中的先后顺序是固定的,通常情况下,开发人员要按照官方提供的元素顺序编写配置文件,否则,MyBatis会在解析配置文件时报错。
2、<properties>元素
<properties>是一个用于配置属性的元素,MyBatis支持<properties>元素的两种配置方式:通过<property>子元素或通过properties文件。
1、通过子元素<property>
<properties>元素通过其子元素<property>完成属性传递,在MyBatis的配置文件中添加<properties>元素,具体代码如下。
<properties>
<property name= "driver" value= "com.mysql.jdbc.Driver">
<property name= "url" value= "jdbc:mysql://localhost:3306/chapter02">
<property name= "username" value= "admin">
<property name= "password" value= "admin">
<properties>
2、通过properties文件
在resource目录下新建一个db.properties文件,具体代码如下。
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/chapter02
username = admin
password = admin
在Mybatis的配置文件中导入properties文件,具体代码如下。
<properties resource="db.properties"/>
在完成上述配置后,<dataSource>元素的代码可直接引用<properties>元素中的信息,具体代码如下。
<dataSource type="POOLED">
<property name="driver" value= "${driver }" />
<property name="url" value= "${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password} "/>
</dataSource>
在以上代码中,${}表示引用<properties>的内容。
<properties resource="db.properties">
<property name= "driver" value= "com.mysq1.jdbc.Driver">
<property name= "url" value="jdbc:mysql://localhost:3306/chapter02">
<property name= "username" value= "admin">
<property name= "password" value= "admin">
<properties>
MyBatis按照下面的顺序来加载:
- 首先读取在properties元素体内指定的属性。
- 然后根据properties元素中的resource属性读取类路径下属性文件,或根据url属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
- 最后读取作为build()方法的参数传递的属性,并覆盖之前读取过的同名属性。
从MyBatis 3.4.2开始,你可以为占位符指定一个默认值。例如:
<dataSource type="POOLED">
<property name="username" value="${username:admin}"/><!--如果属性'username'没有被配置,'username'属性的值将为'admin' -->
</dataSource>
这个特性默认是关闭的。要启用这个特性,需要添加一个特定的属性来开启这个特性。例如:
<properties resource= "db.properties">
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/><!--启用默认值特性-->
</properties>
如果你在属性名中使用了":"字符(如:db:username)就需要设置特定的属性来修改分隔属性名和默认值的字符。例如:
<properties resource="org/mybatis/examplelconfig.properties">
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator"value="?:"/><!--修改默认值的分隔符-->
</properties>
<dataSource type="POOLED">
<property name="username" value="${db:username?:ut_user} ">
</dataSource>
3、<setting>元素
<settings>是MyBatis 中较为复杂的配置元素,同时也包含重要的配置内容,这些内容控制着MyBatis运行时的状态和行为。
4、<typeAliases>元素
MyBatis支持使用别名。别名就是设置一个缩写名字。它仅用于XML配置,意在降低冗余的全限定类名书写。
别名的设置一般通过配置文件中的<typeAliases>元素进行,具体示例代码如下。
<typeAliases>
<typeAlias alias="StudentPOJO" type="cn.edu.hnit.example.chapter01.model.StudentPOJO">
<typeAliases>
除此之外,MyBatis还支持通过扫描包的形式设置别名,具体示例代码如下。
<typeAliases>
<package name="cn.edu.hnit.example.chapter01.model">
<typeAliases>
每一个在包 cn.edu.hnit.example.chapter01.model 中的Java Bean,在没有注解的情况下,会使用Bean的首字母小写的非限定类名来作为它的别名(实际parameterType和resultType不区分大小写)。比如model.StudentPOJO 的别名为studentPOJO,若有注解,则别名为其注解值。
@Alias("student")
public class StudentPOJO{
}
别名的优先级从上往下依次为:
- <typeAlias>标签
- @Alias注解
- <package>标签
为了方便开发,MyBatis为一些常用的Java类型提供了别名,具体如表所示。
5、<typeHandlers>元素
各数据库的数据类型会存在差异,有些数据类型是通用的,有些是专属的。为了屏蔽这些数据类型的差异,Java提供了JDBC类型,将它与数据库类型做映射。
JDBC在java.sql.Types类中定义了一系列的常规SQL类型标识符。这些类型可用于表示最为常用的SQL类型。在用JDBC API编程时,程序员通常可以使用这些JDBC类型来引用一般的SQL类型,而无须关心目标数据库所用的确切SQL类型的名称。
Java类型与JDBC类型也存在差异,两者间的映射表部分如下:
执行带参数SQL,我们调用preparedStatement.set**()方法,参数为Java类型,而实际数据库接受的参数是数据库支持的数据类型,这期间就包含了Java类型到JDBC数据类型的转化,JDBC数据类型到数据库的数据类型的转换。从结果集中取值时,需要经过反向转化。
MyBatis通过typeHandler完成JDBC与Java类型间的转换。
typeHandler为类型处理器,它的核心功能是根据需要将数据由Java类型转化成JDBC类型,或者由JDBC类型转化为Java类型。
MyBatis 内部定义了一系列的typeHandler,其中,常用的typeHandler如表所示。
表中列举出了MyBatis 内部定义的typeHandler,这些typeHandler无须显式声明,MyBatis 会自动探测数据类型并完成转换。
MyBatis根据Java类型和JDBC类型与TypeHandler建立映射,在MyBatis解析映射文件时,对于每个待执行SQL都会生成一个MappedStatement,该MappedStatement 会保存每个SQL参数以及返回结果的数据类型,从而根据该类型找到对应的TypeHandler。
同时,Mybatis支持重写已有的类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。
具体有两种方法:
- 实现org.apache.ibatis.type.TypeHandler接口
- 继承 org.apache.ibatis.type.BaseTypeHandler类
TypeHandler类如下所示,setParameter是用于实现Java类型的值到JDBC类型的值的转换,getResult是用于实现JDBC类型的值到Java类型的值的转换。
public interface TypeHandler<T>{
void setParameter(PreparedStatement ps, int i,T parameter, JdbcType jdbcType)throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
BaseTypeHandler抽象类实现TypeHandler接口,并增加了参数非空判断的代码,如果需要继承该类,则需要实现setNonNullParameter、getNullableResult方法。然后通过继承BaseTypeHandler类实现List集合与字符串XXX,XXX,XXX相互映射。
类处理器创建以后,还需要在Mybatis的配置文件中配置类型处理器:
<typeHandlers>
<typeHandler/>
<package/>
</typeHandlers>
<typeHandler>用于注册某个typeHandler,<package>用于注册多个typeHandler。
<package name=""/>
当配置package的时候,mybatis 会去配置的package扫描 TypeHandler
<typeHandler handler=""/>
handler属性直接配置我们要指定的TypeHandler
<typeHandler javaType="" handler=""/>
javaType配置Java类型,例如String,如果配上javaType,那么指定的typeHandler就只作用于指定的类型
<typeHandler jdbcType="" handler=""/>
jdbcType配置数据库基本数据类型,例如varchar,如果配上jdbcType,那么指定的typeHandler就只作用于指定的类型
<typeHandler javaType="" jdbcType="" handler=""/>
两者都配置
类型转换器还可以通过注解配置Java类型和Jdbc类型:
@MappedTypes:注解配置Java类型
@MappedJdbcTypes:注解配置Jdbc类型
@MappedTypes 与@MappedJdbcTypes支持配置多个值,实际上Java类型不需要声明,因为BaseTypeHandler接口就指明Java类型。
以上配置完成后,即可直接使用select语句获取数据,Mybatis 会自动完成结果集与POJO的转换。
如果需要实现自定义Java类型到JDBC类型的转换,需要手动指定参数的类型转换器,否则MyBatis 会采用内置类型转换器,如
<insert id = "insert">
insert into student(student_name, age, course)
values(#{studentName}, #{age}, #{course, typeHandler=ListTypeHandler})
</insert>
6、<ObjectFactory>元素
MyBatis使用一个对象工厂(ObjectFactory)实例来完成结果对象实例化工作。默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。
若需要调用带参数构造方法,则需在ResultMap中设定构造方法的入参,如:
<resultMap id="studentResultMap" type="cn.edu.hnit.example.chapter01.model.StudentPO">
<constructor>
<idArg column="student_id" javaType="int"/>
<arg column="student_name" javaType="string"/>
<arg column="age" javaType="int"/>
<arg column="course" javaType="string"/>
</constructor>
</resultMap>
此时需要注意的是,这种情况下<constructor>参数的顺序必须与构造器一致,参数应给出对应的Java类型,因为MyBatis 会根据参数顺序与类型直接调用有参构造器,因此<constructor>参数的Java类型应与构造器入参的Java类型完全一致,如<constructor>参数的Java类型为_int,则对应构造器参数的Java类型为int,<constructor>参数的Java类型为int,则对应构造器参数的Java类型为Integer。
如需在实例化对象时定制服务,在可实现ObjectFactory接口,或继承ObjectFactory的实现类DefaultObjectFactory。
public class ExampleObjectFactory extends DefaultObjectFactory {
public <T> T create(Class<T> type){ // 无参构造器
//增加业务逻辑
return super.create(type);
}
public Object create(Class<T> type,List<Class<?>> constructorArgTypes,List<Object> constructorArgs){ // 有参构造器
//增加业务逻辑
return super.create(type,constructorArgTypes, constructorArgs);
}
}
7、<environments>元素
MyBatis可以配置成适应多种环境,这种机制有助于将SQL映射应用于多种数据库之中。
注意:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境。
sqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
以上代码加载的是默认环境,如需指定环境,则使用
public SqlSessionFactory build(InputStream inputStream,String environment)
如:
sqlSessionFactory sqlSessionFactory = new sqlSessionFactoryBuilder().build(inputStream,"development”);
<environments default="development">
<environment id="development">
...
</environment>
<environment id="test">
...
</environment>
</environments>
<environments>标签中default属性用来指定默认环境使用的是哪个子元素<environment>的配置。<environment>的id属性用来唯一标识该环境。
MyBatis的运行环境信息包括事务管理器和数据源。
MyBatis通过<environment>元素定义一个运行环境,进而通过子元素<transactionManager>配置事务管理器,通过<dataSource>配置数据源,具体示例代码如下。
<environment id="development">
<transactionManager type="JDBC"/>
<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>
在MyBatis 中有两种类型的事务管理器(也就是type="[JDBC|MANAGED]")。
- JDBC:这个配置直接使用了JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED:这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如J2EE 应用服务器的上下文)。默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将closeConnection属性设置为false来阻止默认的关闭行为。
<dataSource>元素使用标准的JDBC数据源接口来配置JDBC 连接对象的资源,有三种内建的数据源类型(也就是type="[UNPOOLED|POOLED|JNDI]")。
1、UNPOOLED
非连接池类型,这个数据源的实现会每次请求时打开和关闭连接。UNPOOLED类型的数据源仅仅需要配置5种属性。
2、POOLED
连接池类型,POOLED是一种使并发Web应用快速响应请求的流行处理方式,由于它维持有一定活跃量的连接对象,因此,它适用于对性能有一定要求的应用程序。
除了上述UNPOOLED类型中提及的属性,POOLED 数据源还可以配置更多的属性:
- poolMaximumActiveConnections:数据库连接池中最多存在的活跃连接数,默认值为10,0表示无限制,通常设置为数据库访问可能的并发量。
- poolMaximumIdleConnections:数据库连接池中最多存在的空闲连接数,实际空闲连接数超过该设置时,会强制关闭空闲连接数,0表示无限制。
- poolMaximumCheckoutTime:最大可回收时间,即当达到最大活动链接数时此时如果有程序获取连接,则检查最先使用的连接,看其是否超出了该时间,如果超出了该时间,则强制回收该连接。默认值为20秒,单位为毫秒。
- poolTimeToWait:最长等待获取连接时间,若超时则打印状态日记并重新尝试获取连接。默认值为20秒,单位为毫秒。
- poolPingQuery:发送到数据库的侦测查询,用于检验连接是否处在正常工作秩序并准备接受请求。默认不侦测。
- poolPingEabled:是否启动侦测查询。若开启,这必须使用一个可执行的SQL设置poolPingQuery属性(最好是一个非常快的SQL,减少检测所消耗的时间),默认值为false。
- poolPingConnectionsNotUsedFor:配置poolPingQuery的使用频度。默认值为0,单位为毫秒。当从连接池中拿出的连接闲置超过指定时间,就会对它进行ping。
3、JNDI
这个数据源实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。这种数据源配置只需要两个属性:
- initial_context:这个属性用来在InitialContext中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么data_source属性将会直接从InitialContext中寻找。
- data_source:这是引用数据源实例位置的上下文的路径。提供了initial_contex配置时会在其返回的上下文中进行查找,没有提供时则直接在InitialContext中查找。
8、<mappers>元素
<mappers>元素用于引导MyBatis找到映射文件并解析其中的映射信息。映射文件包含了POJO对象和数据表之间的映射信息,SQL语句与Java接口的映射关系。
通过<mappers>元素引入映射文件有4种方法,具体如下。
1、使用相对于类路径的资源引用
<mappers>
<mapper resource="cn/edu/hnit/example/mapper/StudentMapper.xml"/>
</mappers>
2、使用完全限定资源定位符(本地文件路径)
<mappers>
<mapper url="file:///var/mappers/StudentMapper.xml"/>
</mappers>
3、使用映射器接口实现类的完全限定类名
<mappers>
<mapper class="cn.edu.hnit.example.mapper.StudentMapper"/>
</mappers>
该方法必须保证XML文件与Java接口位于统一路径下,且同名。
4、将包内的映射器接口实现全部注册为映射器
<mappers>
<package name="n.edu.hnit.example.mapper"/>
</mappers>
该方法必须保证XML文件与Java接口位于统一路径下,且同名。