最近又搞起mybatis&spring的事儿啦, 所有的东西早忘光了。 再次总结一遍。
mybatis&spring 最小集
1)pom.xml<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.25</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!-- context 依赖 core、 bean 、aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<!-- 对管理db 的一系列封装 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
2) 手工得到 spring 的 ApplicationContext
/**
* 测试基类
* 最基础的测试形式,自己手动构建ApplicationContext
* 没有使用 Spring test 框架进行的单元测试
*/
public abstract class TestCaseBase {
protected static ApplicationContext ac = null;
/**
* 配置文件
*/
private static String[] configXml = {
"spring-application.xml",
"dataSource-config.xml"
};
static {
ac = new ClassPathXmlApplicationContext(configXml);
}
// 在其子类中可直接从 ac 中get 到 需要的bean,例如
//CabinetMapper cabinetMapper = (CabinetMapper) ac.getBean("cabinetMapper");
}
3)dataSource-config.xml
<!-- 配置一个数据源 -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/xiaobing?useSSL=true"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</bean>
<!-- mybatis 生成查询的 入口 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataSource" />
<!-- mybatis 除环境之外的 所有配置文件所在的位置,此处的路径是相对于classpath的 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
</bean>
其中 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>
<typeAliases>
<!-- 使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author -->
<!--<package name="com.cainiao.wmpintell.manager.entity"/> -->
<!-- 等价于
<typeAlias alias="cabinetStationMappingDO" type="com.cainiao.wmpintell.manager.entity.CabinetStationMappingDO" />
-->
<typeAlias alias="CabinetDO" type="com.taobao.wms.common.entity.CabinetDO" />
</typeAliases>
<mappers>
<!-- 这里的路径也是相对于classpath的, 但写法和 上面的不一样 -->
<mapper resource="mybatis/mapper/sqlmap-CabinetMapper.xml"/>
</mappers>
</configuration>
在sqlmap-CabinetMapper.xml 中 所有的 sql 都要写在 和 CabinetMapper 接口 完全限定名 一模一样的 命名空间中。
<mapper namespace="com.taobao.wms.dal.space.CabinetMapper">
</mapper>
4)spring-application.xml 自动以代理的形式实现所有Mapper
<!-- 其内部使用了 sqlSessionFactory -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.taobao.wms.dal.space" />
</bean>
是对
SqlSession session = sqlSessionFactory.openSession();
try {
CabinetDO cabinet = (CabinetDO) session.selectOne(
"com.taobao.wms.dal.space.CabinetMapper.findByPrimaryKey", 101);
} finally {
session.close();
}
这个过程的 自动化实现。 其实现原理如下:
Q1:mapper 如何 通过 sqlmap-XXX.xml 调用到 mysql?
既 AddressMapper mapper = session.getMapper(AddressMapper.class);
Address address = mapper.queryById(101);
这两句到底会执行什么?
MapperMethod 下面
一个是:SqlCommand
String statementName = mapperInterface.getName() + "." + method.getName();
MappedStatement ms = null;
if (configuration.hasStatement(statementName)) {
ms = configuration.getMappedStatement(statementName);
}
name = ms.getId();
type = ms.getSqlCommandType();
另一个是:
MethodSignature
用于说明方法的一些信息,主要有返回信息
最终 方法执行时:execute(SqlSession sqlSession, Object[] args)
会执行:
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
Address address = session.selectOne("org.mybatis.example.AddressMapper.queryById", 101);
statement 标识: 是 sqlmap-XXX.xml 下的namespace+ id
/**
* Retrieve a single row mapped from the statement key and parameter.
* @param <T> the returned object type
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @return Mapped object
*/
<T> T selectOne(String statement, Object parameter);
底层基于
MappedStatement ms = configuration.getMappedStatement(statement);
MyBatis框架会把每一个节点(如:select节点、delete节点)生成一个MappedStatement类。
executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
在Manger层 使用 的dao/mapper 是从Spring中取出来的,
spring为每个mapper 接口 都是 实例化一个MapperFactoryBean
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);
}