自定义持久层框架MyORMFramework—框架实现
Posted 共饮一杯无
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义持久层框架MyORMFramework—框架实现相关的知识,希望对你有一定的参考价值。
框架端
定义数据源配置和映射语句实体
Configuration
@Data
public class Configuration
private DataSource dataSource;
/**
* key: statementId value:封装好的mappedStatement对象
*/
Map<String,MappedStatement> mappedStatementMap = new HashMap<>();
MappedStatement
@Data
public final class MappedStatement
private String id;
/**
* sql语句
*/
private String sql;
/**
* 参数值类型
*/
private Class<?> parameterType;
/**
* 返回值类型
*/
private Class<?> resultType;
定义配置文件访问的工具类
public class Resources
/**
* 根据配置文件的路径,将配置文件加载成字节输入流,存储在内存中
*
* @param path
* @return
*/
public static InputStream getResourceAsSteam(String path) throws IOException
InputStream in = Resources.class.getClassLoader().getResourceAsStream(path);
if (in == null)
throw new IOException("找不到资源" + path);
return in;
定义SqlSessionFactoryBuilder
public class SqlSessionFactoryBuilder
private Configuration configuration;
public SqlSessionFactoryBuilder()
this.configuration = new Configuration();
public SqlSessionFactory build(InputStream inputStream) throws
DocumentException, PropertyVetoException, ClassNotFoundException
//1.dom4j解析配置⽂件,封装Configuration
XMLConfigerBuilder xmlConfigerBuilder = new
XMLConfigerBuilder(configuration);
Configuration configuration =
xmlConfigerBuilder.parseConfiguration(inputStream);
//2.创建SqlSessionFactory对象(工厂类),生产sqlSession:会话对象
SqlSessionFactory sqlSessionFactory = new
DefaultSqlSessionFactory(configuration);
return sqlSessionFactory;
数据源配置和映射语句解析XMLConfigBuilder、XMLMapperBuilder
XMLConfigBuilder
public class XMLConfigerBuilder
private Configuration configuration;
public XMLConfigerBuilder()
this.configuration = new Configuration();
/**
* 该方法就是使用dom4j对配置文件进行解析,封装Configuration
*/
public Configuration parseConfig(InputStream inputStream) throws DocumentException, PropertyVetoException, IOException, ClassNotFoundException
Document document = new SAXReader().read(inputStream);
//<configuration>
Element rootElement = document.getRootElement();
List<Element> list = rootElement.selectNodes("//property");
Properties properties = new Properties();
for (Element element : list)
String name = element.attributeValue("name");
String value = element.attributeValue("value");
properties.setProperty(name, value);
//连接池
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
comboPooledDataSource.setUser(properties.getProperty("username"));
comboPooledDataSource.setPassword(properties.getProperty("password"));
configuration.setDataSource(comboPooledDataSource);
//mapper.xml解析: 拿到路径--字节输入流---dom4j进行解析
List<Element> mapperList = rootElement.selectNodes("//mapper");
for (Element element : mapperList)
String mapperPath = element.attributeValue("resource");
InputStream resourceAsSteam = Resources.getResourceAsSteam(mapperPath);
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
xmlMapperBuilder.parse(resourceAsSteam);
return configuration;
XMLMapperBuilder
public class XMLMapperBuilder
private Configuration configuration;
public XMLMapperBuilder(Configuration configuration)
this.configuration = configuration;
public void parse(InputStream inputStream) throws DocumentException,
ClassNotFoundException
Document document = new SAXReader().read(inputStream);
Element rootElement = document.getRootElement();
String namespace = rootElement.attributeValue("namespace");
List<Element> select = rootElement.selectNodes("select");
for (Element element : select)
//id的值
String id = element.attributeValue("id");
String parameterType = element.attributeValue("parameterType");
String resultType = element.attributeValue("resultType");
//输⼊参数class
Class<?> parameterTypeClass = getClassType(parameterType);
//返回结果class
Class<?> resultTypeClass = getClassType(resultType);
//statementId
String key = namespace + "." + id;
//sql语句
String textTrim = element.getTextTrim();
//封装 mappedStatement
MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setId(id);
mappedStatement.setParameterType(parameterTypeClass);
mappedStatement.setResultType(resultTypeClass);
mappedStatement.setSql(textTrim);
//填充 configuration
configuration.getMappedStatementMap().put(key, mappedStatement);
private Class<?> getClassType (String parameterType) throws
ClassNotFoundException
Class<?> aClass = Class.forName(parameterType);
return aClass;
SqlSessionFactory 接口及DefaultSqlSessionFactory 实现类
SqlSessionFactory
public interface SqlSessionFactory
SqlSession openSession();
DefaultSqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory
private Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration)
this.configuration = configuration;
@Override
public SqlSession openSession()
return new DefaultSqlSession(configuration);
SqlSession 接口及 DefaultSqlSession 实现类
SqlSession
public interface SqlSession
/**
* 查询所有
*
* @param statementId
* @param params
* @param <E>
* @return
* @throws Exception
*/
<E> List<E> selectList(String statementId, Object... params) throws Exception;
/**
* 根据条件查询单个
*
* @param statementId
* @param params
* @param <T>
* @return
* @throws Exception
*/
<T> T selectOne(String statementId, Object... params) throws Exception;
DefaultSqlSession
public class DefaultSqlSession implements SqlSession
private Configuration configuration;
public DefaultSqlSession(Configuration configuration)
this.configuration = configuration;
@Override
public <E> List<E> selectList(String statementid, Object... params) throws Exception
//将要去完成对simpleExecutor里的query方法的调用
SimpleExecutor simpleExecutor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
return (List<E>) list;
@Override
public <T> T selectOne(String statementid, Object... params) throws Exception
List<Object> objects = selectList(statementid, params);
if (objects.size() == 1)
return (T) objects.get(0);
else
throw new RuntimeException("查询结果为空或者返回结果过多");
SQL执行器接口和实现类Executor、SimpleExecutor
Executor
public interface Executor
/**
* 执行查询SQL
* @param configuration
* @param mappedStatement
* @param params
* @param <E>
* @return
* @throws Exception
*/
<E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception;
SimpleExecutor
/**
* SQL执行器实现
*
* @author zjq
* @date 2022/3/15
*/
public class SimpleExecutor implements Executor
@Override
public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception
// 1. 注册驱动,获取连接
Connection connection = configuration.getDataSource().getConnection();
// 2. 获取sql语句 : select * from user where id = #id and username = #username
//转换sql语句: select * from user where id = ? and username = ? ,转换的过程中,还需要对#里面的值进行解析存储
String sql = mappedStatement.getSql();
BoundSql boundSql = getBoundSql(sql);
// 3.获取预处理对象:preparedStatement
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
// 4. 设置参数
//获取到了参数的全路径
String paramterType = mappedStatement.getParamterType();
Class<?> paramtertypeClass = getClassType(paramterType);
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
for (int i = 0; i < parameterMappingList.size(); i++)
ParameterMapping parameterMapping = parameterMappingList.get(i);
String content = parameterMapping.getContent();
//反射
Field declaredField = paramtertypeClass.getDeclaredField(content);
//暴力访问
declaredField.setAccessible(true);
Object o = declaredField.get(params[0]);
preparedStatement.setObject(i + 1, o);
// 5. 执行sql
ResultSet resultSet = preparedStatement.executeQuery();
//String resultType = mappedStatement.getResultType();
//Class<?> resultTypeClass = getClassType(resultType);
Class<?> resultTypeClass = mappedStatement.getResultType();
ArrayList<Object> objects = new ArrayList<>();
// 6. 封装返回结果集
while (resultSet.next())
Object o = resultTypeClass.newInstance();
//元数据
ResultSetMetaData metaData = resultSet.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++)
// 字段名
String columnName = metaData.getColumnName(i);
// 字段的值
Object value = resultSet.getObject(columnName);
//使用反射或者内省,根据数据库表和实体的对应关系,完成封装
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(o, value);
objects.add(o);
return (List<E>) objects;
private Class<?> getClassType(String paramterType) throws ClassNotFoundException
if (paramterType != null)
Class<?> aClass = Class.forName(paramterType);
return aClass;
return null;
/**
* 完成对#的解析工作:1.将#使用?进行代替,2.解析出#里面的值进行存储
*
* @param sql
* @return
*/
private BoundSql getBoundSql(String sql)
//标记处理类:配置标记解析器来完成对占位符的解析处理工作,主要是配合通⽤标记解析器GenericTokenParser类完成对配置⽂件等的解析⼯作,其中TokenHandler主要完成处理
ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
//GenericTokenParser :通⽤的标记解析器,完成了代码⽚段中的占位符的解析,然后再根据给定的标记处理器(TokenHandler)来进⾏表达式的处理
//三个参数:分别为openToken (开始标记)、closeToken (结束标记)、handler (标记处理器)
GenericTokenParser genericTokenParser = new GenericTokenParser("#", "", parameterMappingTokenHandler);
//解析出来的sql
String parseSql = genericTokenParser.parse(sql);
//#里面解析出来的参数名称
List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
BoundSql boundSql = new BoundSql(parseSql, parameterMappings);
return boundSql;
使用端
创建 sqlMapConfig.xml
<configuration>
<!--数据库配置信息-->
<dataSource>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///my-orm-framework"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
<!--存放mapper.xml的全路径-->
<mapper resource="UserMapper.xml"></mapper>
</configuration>
创建对应的mapper.xml
<mapper namespace="com.zjq.dao.IUserDao">
<!--sql的唯一标识:namespace.id来组成 : statementId-->
<select id="findAll" resultType="com.zjq.pojo.User" >
select * from user
</select>
<!--
User user = new User()
user.setId(1);
user.setUsername("zhangsan")
-->
<select id="findByCondition" resultType="com.zjq.pojo.User" paramterType="com.zjq.pojo.User">
select * from user where id = #id and username = #username
</select>
</mapper>
UserDao
public interface IUserDao
//查询所有用户
public List<User> findAll() throws Exception;
//根据条件进行用户查询
public User findByCondition(User user) throws Exception;
User实体
@Data
public class User
private Long id;
private String username;
private String password;
框架查询验证
@Test
public void test() throws Exception
InputStream resourceAsSteam = Resources.getResourceAsSteam("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsSteam);
SqlSession sqlSession = sqlSessionFactory.openSession();
//调用
User user = new User();
user.setId(1);
user.setUsername("张三");
User user2 = sqlSession.selectOne("user.selectOne", user);
System.out.println(user2);
List<User> users = sqlSession.selectList("user.selectList");
for (User user1 : users)
System.out.println(user1);
以上是关于自定义持久层框架MyORMFramework—框架实现的主要内容,如果未能解决你的问题,请参考以下文章