Mybatis
在Mybatis3问世之前,Spring3的开发工作就已经完成了,所以Spring3中还是没有对Mybatis3的支持。因此Mybatis社区自己开发了一个Mybatis-Spring用来满足Mybatis用户整合Spring的需求。
下面将分别介绍Mybatis不整合与整合Spring的具体区别,首先介绍不整合Spring的情形下,如何配置和使用Mybatis。每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,SqlSessionFactory实例通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder从一个xml配置文件或者一个预定义的配置类的实例获得配置信息。以下一个mybatis-config.xml的配置文件,在这个文件中内容会在Spring使用过程中被划分成几个部分。其中settings部分对应configLocation属性,environments部分对应dataSource属性,mappers部分对应mapperLocations属性。
<?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">
<!-- XML 配置文件1.包含对Mybatis系统的核心设置,2.包含获取数据库连接实例的数据源和 决定事务范围和控制的事务管理器. -->
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<!-- 配置JDBC连接参数 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 指明每个关系表的配置文件 -->
<mappers>
<mapper resource="org/phf/mapping/UserMapper.xml"/>
<mapper resource="org/phf/mapping/ClazzMapper.xml"/>
<mapper resource="org/phf/mapping/StudentMapper.xml"/>
</mappers>
</configuration>
其中一个UserMapper.xml文件如下:
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"mybatis-3-mapper.dtd">
<!-- Mybatis的构建就是聚焦于SQL的,使其远离于普通的方式。Mybatis封装处理了连接和查询结果获取 -->
<mapper namespace="org.phf.mapping.UserMapper">
<!--开启缓存-->
<cache />
<!-- select 查询语句是使用 MyBatis 时最常用的元素之一。id(方法)是 get, parameterType(参数类型)是Integer, resultType(返回类型)是 User对象,其属性就是列名,值是列对应的值。-->
<select id=“find” parameterType=“Integer” resultType=“User”>
SELECT * FROM TB_USER WHERE ID = #{id}
</select>
</mapper>
通过namespace关联一个接口,其中id为接口中的具体方法,下面是该UserMapper接口
//UserMapper.java
package org.phf.mapping;
import org.phf.pojo.User;
/**
* 只要定义接口方法,所需sql语句在相应UserMapper.xml中映射
**/
public interface UserMapper {
//一条数据可以返回表对象,属性对应列名
User find(Integer id);
}
下面是程序中解析配置文件,注意SqlSessionFactoryBuilder,sqlSessionFactory,SqlSession这3个主意类。在Spring中将直接由Spring容器进行管理,只需要在配置文件中建立关联。
package org.phf.factory;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisFactory {
/**
* SqlSessionFactory对象可以看成DataSource(数据库连接池)
* 在应用执行期间,应该只创建一次,建议使用单例模式
* 通过SqlSessionFactoryBuilder来获得数据库配置参数并创建
*/
private static SqlSessionFactory sqlSessionFactory;
/**
* SqlSession对象可以理解成对Connection的封装,即一个数据连接会话
* 它同时也封装了连接和断开过程,提供sql语句的映射
* SqlSession实例不能被共享,它不是线程安全的。
* 所以应该一次性用完后要确保使用finally块来关闭它,关闭时会被收回SqlSessionFactory所管理的连接池中
*/
//private static SqlSession session;
static
{
try {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
System.out.println(sqlSessionFactory);
} catch (Exception e) {
e.printStackTrace();
}
}
//
public static SqlSession getSqlSession()
{
return sqlSessionFactory.openSession();
}
//
public static void close(SqlSession session)
{
if(session != null)
session.close();
}
}
最后通过
session = MybatisFactory.getSqlSession();
//获取业务接口,通过接口类型获取由Mybatis生成的匿名实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//调用接口方法,执行操作且获得数据
System.out.println("<---------find by id----------->");
User user = userMapper.find(1);
经过上面的介绍,对Mybatis的基本用法已经有了一些了解,下面介绍结合Spring情况下使用Mybatis的使用方式。
Mybatis的所有操作都是基于一个SqlSession的,而SqlSession是由SqlSessionFactory来产生的,SqlSessionFactory又是由SqlSessionFactoryBuilder来生成的。在使用Mybatis-Spring的时候,同样也需要SqlSession,而且这个SqlSession是内嵌在程序中的,一般不需要直接访问。
因此Mybatis-Spring封装了一个SqlSessionFactoryBean,在SqlSessionFactoryBean里面是通过SqlSessionFactoryBuilder来生成相应的SqlSessionFactory,再由SqlSessionFactory生成相应的SqlSession。所以需要在Spring的applicationContext配置文件中定义一个SqlSessionFactoryBean,此外可以通过对SqlSessionFactoryBean指定一些属性来提供关于Mybatis的一些配置信息:
<bean id=“sqlSessionFactory” class=“org.mybatis.spring.SqlSessionFactoryBean”>
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis.xml" />
<property name="mapperLocations" value="classpath:mapper/**/*.xml" />
</bean>
dataSource属性是必须指定的,它表示用于连接数据库的数据源,其中dataSource,使用c3p0建立数据库连接池:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>${jdbc.driverClassName}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<!--连接池中保留的最小连接数。 -->
<property name="minPoolSize" value="10" />
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize" value="100" />
<!--最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="0" />
<property name="maxConnectionAge" value="1200" />
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="3" />
<property name="maxStatements" value="1000" />
<property name="initialPoolSize" value="3" />
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="0" />
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts" value="1" />
<property name="breakAfterAcquireFailure" value="false" />
<property name="testConnectionOnCheckout" value="false" />
<property name="testConnectionOnCheckin" value="false" />
<property name="acquireRetryDelay" value="100" />
<property name="autoCommitOnClose" value="false" />
</bean>
其中mybatis.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>
<settings>
<setting name="cacheEnabled" value="false"/>
</settings>
<typeAliases></typeAliases>
</configuration>
另外包括:
- mapperLocations:它表示我们的Mapper文件存放的位置,当我们的Mapper文件跟对应的Mapper接口处于同一位置的时候可以不用指定该属性的值。
- configLocation:用于指定Mybatis的配置文件位置。如果指定了该属性,那么会以该配置文件的内容作为配置信息构建对应的SqlSessionFactoryBuilder,但是后续属性指定的内容会覆盖该配置文件里面指定的对应内容。
- typeAliasesPackage:它一般对应我们的实体类所在的包,这个时候会自动取对应包中不包括包名的简单类名作为包括包名的别名。多个package之间可以用逗号或者分号等来进行分隔。
- typeAliases:数组类型,用来指定别名的。指定了这个属性后,Mybatis会把这个类型的短名称作为这个类型的别名,前提是该类上没有标注@Alias注解,否则将使用该注解对应的值作为此种类型的别名。
- plugins:数组类型,用来指定Mybatis的Interceptor。
- typeHandlersPackage:用来指定TypeHandler所在的包,如果指定了该属性,SqlSessionFactoryBean会自动把该包下面的类注册为对应的TypeHandler。多个package之间可以用逗号或者分号等来进行分隔。
- typeHandlers:数组类型,表示TypeHandler。
接下来就是在Spring的applicationContext文件中定义Mapper对象相关的MapperFactoryBean。通过MapperFactoryBean可以获取到我们想要的Mapper对象。MapperFactoryBean实现了Spring的FactoryBean接口,所以MapperFactoryBean是通过FactoryBean接口中定义的getObject方法来获取对应的Mapper对象的。在定义一个MapperFactoryBean的时候有两个属性需要注入,一个是Mybatis-Spring用来生成SqlSessionTemplate(实现了SqlSession接口)对象的sqlSessionFactory;另一个就是已经定义的Mapper接口。
定义好相应Mapper接口对应的MapperFactoryBean之后,就可以把对应的Mapper接口注入到由Spring管理的bean对象中了,比如Service bean对象。这样当需要使用到相应的Mapper接口时,MapperFactoryBean会从它的getObject方法中获取对应的Mapper接口,而getObject内部还是通过注入的属性调用SqlSession接口的getMapper(Mapper接口)方法来返回对应的Mapper接口的。这样就通过把SqlSessionFactory和相应的Mapper接口交给Spring管理实现了Mybatis跟Spring的整合。
<bean id="blogMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface"
value="org.phf.mapping.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
利用上面的方法进行整合的时候,有一个Mapper就需要定义一个对应的MapperFactoryBean,每个bean通过第一个属性与一个接口进行绑定(类似于不结合Spring方式中传递的User.class实现)。当Mapper比较少的时候,这样做也还可以,但是当Mapper相当多时再这样定义一个个Mapper对应的MapperFactoryBean就显得速度比较慢了。为此Mybatis-Spring提供了一个叫做MapperScannerConfigurer的类,通过这个类Mybatis-Spring会自动注册Mapper对应的MapperFactoryBean对象。对于MapperScannerConfigurer而言有一个属性必须指定的,那就是basePackage。basePackage是用来指定Mapper接口文件所在的基包的,在这个基包或其所有子包下面的Mapper接口都将被搜索到。
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.tiantian.mybatis.mapper" />
</bean>