背景
我们大多项目都使用了Mybatis。Mybatis的中的sql大多都是配置在xml文件中的,我们为了方便dba对sql统一的管理需要将sql保存在数据库中。这样就要求Mybatis从数据库中加载配置,同时dba优化sql之后还得实现让Mybatis在不重启应用的情况下动态加载。要实现这些功能,需要对Mybatis进行扩展,所以本人花了一些时间分析一Mybatis3源码,在此记录。
分析计划
主要分析如下三大内容:
- 分析Mybatis是怎么解析配置文件
- 分析Mybatis是如何执行Sql并映射结果
- 分析Mybatis是如何使用缓存的
技术要求
- core java。尤其是jdbc部分。
- 基本的xml知识。
- 以上都具备的话,还需要花点时间看看Mybatis:http://mybatis.org/mybatis-3/zh/
环境准备
在eclipse中新建一个普通的maven工程,并加上Mybatis的依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ashan</groupId>
<artifactId>mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
</project>
数据模型
电信行业最简单的三户模型:客户、用户、账户
- 客户:即一个证件对应一个客户
- 用户:一个电话号码或宽带账号对应一个用户
- 账户:一个银行账户对应一个账户
这里假定这个情形:你拿身份证去电信运营商里办了一个号码,并且提供了两个银行账户,每个月都可以使用这两个账号自动交话费。
用户定义
package com.ashan.mybatis;
import java.util.List;
/**
* 用户
*
* @author ashan
*
*/
public class User
{
/**
* 用户id,主键
*/
private String id;
private String username;
/**
* 用户号码
*/
private String svcnum;
private String password;
/**
* 一个用户只能对应一个客户
*/
private Cust cust;
/**
* 一个用户可以有多个账户
*/
private List<Acct> accts;
/**
* 用户类型,两种:普通用户和重要用户
*/
private UserType type;
public User(String id, String username)
{
super();
this.id = id;
this.username = username;
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public Cust getCust()
{
return cust;
}
public void setCust(Cust cust)
{
this.cust = cust;
}
public List<Acct> getAccts()
{
return accts;
}
public void setAccts(List<Acct> accts)
{
this.accts = accts;
}
public UserType getType()
{
return type;
}
public void setType(UserType type)
{
this.type = type;
}
public String getSvcnum()
{
return svcnum;
}
public void setSvcnum(String svcnum)
{
this.svcnum = svcnum;
}
}
用户定义
package com.ashan.mybatis;
public class Cust
{
private String id;
private String custname;
/**
* 证件号码
*/
private String certNo;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getCustname()
{
return custname;
}
public void setCustname(String custname)
{
this.custname = custname;
}
public String getCertNo()
{
return certNo;
}
public void setCertNo(String certNo)
{
this.certNo = certNo;
}
}
账户定义
package com.ashan.mybatis;
public class Acct
{
private String id;
private String payName;
/**
* 银行账号
*/
private String bankNo;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getPayName()
{
return payName;
}
public void setPayName(String payName)
{
this.payName = payName;
}
public String getBankNo()
{
return bankNo;
}
public void setBankNo(String bankNo)
{
this.bankNo = bankNo;
}
}
用户类型
package com.ashan.mybatis;
public enum UserType
{
/**
* 普通用户
*/
GENERAL,
/**
* 重要用户
*/
IMPORTANT
}
Mybatis配置
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>
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
UserMapper.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.ashan.user">
<resultMap type="com.ashan.mybatis.User" id="detailUserResultMap">
<constructor>
<idArg column="user_id" javaType="String"/>
<arg column="user_name"/>
</constructor>
<result property="password" column="user_pwd" />
<result property="type" column="user_type" javaType="com.ashan.mybatis.UserType" typeHandler="com.ashan.mybatis.UserTypeHandler"/>
<result property="svcnum" column="svc_num" />
<association property="cust" javaType="com.ashan.mybatis.Cust">
<id property="id" column="cust_id"/>
<result property="custname" column="cust_name"/>
<result property="certNo" column="cert_no"/>
</association>
<collection property="accts" ofType="com.ashan.mybatis.Acct">
<id property="id" column="acct_id" />
<result property="payName" column="pay_name"/>
<result property="bankNo" column="bank_no"/>
</collection>
</resultMap>
<select id="selectUserDetail" resultMap="detailUserResultMap">
<![CDATA[
select user_id,user_name,user_type,cust_id from tf_f_user a where a.user_id=#{userId}
]]>
</select>
</mapper>
跑跑试试看有没有问题
package com.ashan.mybatis;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class SqlSesstionFactoryTest
{
public static void main(String[] args) throws Exception
{
String resouce="mybatis-config.xml";
InputStream is=Resources.getResourceAsStream(resouce);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
System.out.println(sqlSessionFactory.getConfiguration());
}
}
运行没有异常说明配置OK!
其他说明
搭建这个环境的作用是为了在分析代码过程中进行Debuger,有些时候源代码很难明白,Debuger一下能知道代码的走向,有时源代码看明白了,Debuger一下也能帮助验证自己的理解是否有错。Debuger对分析源码非常有用。
使用Maven构建这个工程除了方便jar导入之后,还有一个用处就是在eclipse中查看源代码非常方便。在eclipse使用maven工程,eclipse会自动下载并关联源代码。