自定义持久层框架MyORMFramework—框架实现

登山则情满于山,观海则意溢于海。这篇文章主要讲述自定义持久层框架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);

自定义持久层框架MyORMFramework—框架实现

文章图片


    推荐阅读