一、使用dom4j解析mybatis核心配置文件
1.1 配置Maven
配置dom4j、jaxen、junit的依赖
<dependencies>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
1.2 读取mybatis-config.xml配置文件
@Test
public void ParseMyBatisConfigXml() throws Exception {
//创建SAXReader对象
SAXReader reader = new SAXReader();
InputStream io = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
//得到整个xml
Document document = reader.read(io);
String xPath = "/configuration/environments";
Element environments = (Element) document.selectSingleNode(xPath);
String aDefault = environments.attributeValue("default");
xPath = "/configuration/environments/environment[@id='"+aDefault+"']";
Element environment = (Element) document.selectSingleNode(xPath);
Element transactionManager = environment.element("transactionManager");
//事务类型
String transactionType = transactionManager.attributeValue("type");
List<Element> dataSources = environment.element("dataSource").elements();
//打印连接源
dataSources.forEach(properties ->{
String name = properties.attributeValue("name");
String value = properties.attributeValue("value");
System.out.println(name+"="+value);
});
xPath = "//mapper";
List<Node> elements = document.selectNodes(xPath);
elements.forEach(element -> {
Element mapper = (Element) element;
String resource = mapper.attributeValue("resource");
System.out.println(resource);
});
}
知识点:xPath = element[@default=‘123’]表示筛选属性default为123的元素
1.3 读取CarMapper.xml文件
/**
* 解析CarMapper.xml文件
*/
@Test
public void ParseSqlConfigXml() throws Exception {
SAXReader reader = new SAXReader();
InputStream io = ClassLoader.getSystemClassLoader().getResourceAsStream("CarMapper.xml");
Document document = reader.read(io);
Element mapper = document.getRootElement();
System.out.println(mapper.attributeValue("namespace"));
List<Element> elements = mapper.elements();
elements.forEach(element -> {
System.out.println(element.attributeValue("id"));
String sql = element.getTextTrim();
//简单正则表达式:[0-9A-Za-z_]* 表示数字+字母+下划线,数量是*个
System.out.println(sql.replaceAll("#\\{[0-9A-Za-z_]*}","?"));
});
}
二、创建基础类
2.1 新建包、基础类
新建utils包,编写Resources类,写入getResourceAsReader()方法
public class Resources {
private Resources(){};
public static InputStream getResourceAsReader(String classPath){
return ClassLoader.getSystemClassLoader().getResourceAsStream(classPath);
}
}
新建core包,新建SqlSessionFactoryBuilder、SqlSessionFactory类:
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder(){};
public SqlSessionFactory build(){
return null;
}
}
2.2 分析SqlSessionFactory类中需要的属性
根据学过MyBatis可以知道,一个environment对应一个数据库,一个environment对应一个SqlSessionFactory
SqlSessionFactory需要写下面信息:
- 事务管理器
- 数据源
- 存放sql语句的map集合
public class SqlSessionFactory {
/**
* 事务管理器
*/
/**
* 数据源
*/
/**
* 存放sql语句的map集合
* key是sqlId
* value是对应的sql标签信息对象
*/
Map<String,MappedStatement> mappedStatements;
}
2.3 事务管理器接口
通过配置文件,知道transaction有两种type,需要灵活切换
所以需要面向接口编程
新建Transaction接口,并编写接口
public interface Transaction {
/**
* 提交事务
*/
void commit();
/**
* 回滚事务
*/
void rollback();
/**
* 关闭事务
*/
void close();
}
2.4 实现事务管理器接口
事务管理器有两个类型, JDBC或者MANAGED,这边只实现JDBC
public class JdbcTransaction implements Transaction{
@Override
public void commit() {
connection.commit();
}
@Override
public void rollback() {
connection.rollback();
}
@Override
public void close() {
connection.close();
}
}
可以发现,要实现JdbcTransaction就必须要有Connection,而Connection从数据源获得
2.5 实现数据源
MyBatis框架中有3个数据源类型:UNPOOLED,POOLED,JNDI
我们只实现第一个
/**
* @author huochai
* @date 2022/10/15 16:45
* 不使用连接池,主要实现这个数据源
*/
public class UnPooledDataSource implements DataSource {
private String url;
private String username ;
private String password ;
public UnPooledDataSource(String url, String username, String password) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
this.url = url;
this.username = username;
this.password = password;
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}