本mybatis只是简单实现,实现mybatis的一部分核心功能。
思路:
- 解析配置文件,得到数据库配置及mapper相关信息
- 创建实体类封装解析到的数据
- 通过动态代理执行sql语句
mapper实体类封装UserMapper.xml的数据:
package com.zhijin.framwork;
public class Mapper {
private String id ;
private String resultType ;
private String sql ;
private String tag ;
private String namespace ;
public Mapper() {
}
public Mapper(String id, String resultType, String sql, String tag, String namespace) {
this.id = id;
this.resultType = resultType;
this.sql = sql;
this.tag = tag;
this.namespace = namespace;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String toString() {
return "Mapper{id = " + id + ", resultType = " + resultType + ", sql = " + sql + ", tag = " + tag + ", namespace = " + namespace + "}";
}
}
创建Configuration封装sqlMapConfig.xml配置
package com.zhijin.framwork;
public class Mapper {
private String id ;
private String resultType ;
private String sql ;
private String tag ;
private String namespace ;
public Mapper() {
}
public Mapper(String id, String resultType, String sql, String tag, String namespace) {
this.id = id;
this.resultType = resultType;
this.sql = sql;
this.tag = tag;
this.namespace = namespace;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String toString() {
return "Mapper{id = " + id + ", resultType = " + resultType + ", sql = " + sql + ", tag = " + tag + ", namespace = " + namespace + "}";
}
}
德鲁伊数据库连接池工厂:
package com.zhijin.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.zhijin.framwork.Configuration;
import com.zhijin.framwork.SqlSession;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;
public class DruidFactoryUtils {
private static DataSource dataSource ;
static {
try {
Configuration configuration = new Configuration();
Properties properties = new Properties();
properties.setProperty("driverClassName",configuration.getDriver());
properties.setProperty("url",configuration.getUrl());
properties.setProperty("username",configuration.getUsername());
properties.setProperty("password",configuration.getPassword());
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void close(SqlSession sqlSession){
try {
if (sqlSession!=null) {
sqlSession.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
SqlSession sqlSession = new SqlSession();
try {
sqlSession.setConnection(dataSource.getConnection());
} catch (Exception e) {
e.printStackTrace();
}
return sqlSession;
}
}
动态代理执行sql
package com.zhijin.framwork;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class SqlSession implements Closeable {
private Connection connection ;
public Connection getConnection() {
return connection;
}
public void setConnection(Connection connection) {
this.connection = connection;
}
@Override
public void close() throws IOException {
}
/**
* 通过动态代理执行查询
* @param obj
* @param <T>
* @return
*/
public <T> T getMapper(Class obj) {
return (T) Proxy.newProxyInstance(obj.getClassLoader(), new Class[]{obj}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1.通过Configuration自加载得到sql语句并执行
Configuration configuration = new Configuration();
List<Mapper> mappers = configuration.getMappers();
Mapper currentMapper =null;
for (Mapper mapper : mappers) {
if (mapper.getNamespace().equals(obj.getName())&& mapper.getId().equals(method.getName())){
currentMapper = mapper;
break;
}
}
String sql = currentMapper.getSql();
PreparedStatement pstm = connection.prepareStatement(sql);
List<Object> datas = new ArrayList<>();
if (currentMapper.getTag().equals("select")){
//处理结果集,封装到list集合中返回给调用
ResultSet rs = pstm.executeQuery();
while (rs.next()){
String resultType = currentMapper.getResultType();
Class clazz = Class.forName(resultType);
Object data = clazz.getDeclaredConstructor().newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
field.set(data,rs.getObject(field.getName()));
}
datas.add(data);
return datas;
}
}else if (currentMapper.getTag().equalsIgnoreCase("update")
|| currentMapper.getTag().equalsIgnoreCase("delete")
|| currentMapper.getTag().equalsIgnoreCase("insert")){
int rows = pstm.executeUpdate();
return rows;
}else {
pstm.execute();
}
return null;
}
});
}
}
测试类:
package com.zhijin.text;
import com.zhijin.bean.User;
import com.zhijin.dao.UserMapper;
import com.zhijin.framwork.SqlSession;
import com.zhijin.utils.DruidFactoryUtils;
import org.junit.Test;
import java.util.List;
public class MybatisTest {
/**
* 测试查询全部
*/
@Test
public void selectAll() {
SqlSession sqlSession = DruidFactoryUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.findAll();
System.out.println(users);
DruidFactoryUtils.close(sqlSession);
}
}