登山则情满于山,观海则意溢于海。这篇文章主要讲述自定义持久层框架MyORMFramework—框架实现相关的知识,希望能为你提供帮助。
框架端
定义数据源配置和映射语句实体
Configuration
@Data
public class Configuration private DataSource dataSource;
/**
*key: statementIdvalue:封装好的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 = https://www.songbingjia.com/android/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
【自定义持久层框架MyORMFramework—框架实现】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 = https://www.songbingjia.com/android/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="https://www.songbingjia.com/android/com.mysql.jdbc.Driver">
<
/property>
<
property name="jdbcUrl" value="https://www.songbingjia.com/android/jdbc:mysql:///my-orm-framework">
<
/property>
<
property name="username" value="https://www.songbingjia.com/android/root">
<
/property>
<
property name="password" value="https://www.songbingjia.com/android/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);
文章图片
推荐阅读
- 自然语言(NLP)处理流程—IF-IDF统计—jieba分词—Word2Vec模型训练使用
- 人工智能机器学习及与智能数据处理Python使用朴素贝叶斯算法对垃圾短信数据集进行分类
- 预测Titanic号上的乘客生存概率_03_优化训练集
- ALS推荐算法—训练并保存—加载并测试
- pyspark_mllib_classifier—(SVM)
- pyspark—WordCount代码
- 创建 spark_session 读取数据-加入缓存-并使用SQL语句分析
- 基于PySpark的航天日志分析(SQL分析)
- 基于物品—SVD餐馆评分估计值